qpid-proton-0.14.0/0000755000175000017500000000000012770711244013327 5ustar danieldanielqpid-proton-0.14.0/.gitattributes0000644000175000017500000000007012770711153016216 0ustar danieldaniel.gitattributes export-ignore .gitignore export-ignore qpid-proton-0.14.0/.mailmap0000644000175000017500000000011112770711153014740 0ustar danieldanielClifford Jansen Ken Giusti qpid-proton-0.14.0/LICENSE0000644000175000017500000002713512770711153014343 0ustar danieldaniel 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. PROTON SUBCOMPONENTS: Proton includes freegetopt with a separate BSD license. Your use of the source code for freegetopt is subject to the terms and conditions of its license in examples/include/pncompat/internal/LICENSE. The setup scripts for the python bindings include files derived by PyZMQ and are licensed with a separate Modified BSD license. Use of the source code in these setup files are subject to the terms and conditions in the license: proton-c/bindings/python/setuputils/PYZMQ_LICENSE.BSD. qpid-proton-0.14.0/README.md0000644000175000017500000000405012770711153014604 0ustar danieldanielQpid Proton - AMQP messaging toolkit ==================================== Linux Build | Windows Build ------------|-------------- [![Linux Build Status](https://travis-ci.org/apache/qpid-proton.svg?branch=master)](https://travis-ci.org/apache/qpid-proton) | [![Windows Build Status](https://ci.appveyor.com/api/projects/status/github/apache/qpid-proton?branch=master&svg=true)](https://ci.appveyor.com/project/ke4qqq/qpid-proton/branch/master) Qpid Proton is a high-performance, lightweight messaging library. It can be used in the widest range of messaging applications, including brokers, client libraries, routers, bridges, proxies, and more. Proton makes it trivial to integrate with the AMQP 1.0 ecosystem from any platform, environment, or language Features -------- + A flexible and capable reactive messaging API + Full control of AMQP 1.0 protocol semantics + Portable C implementation with bindings to popular languages + Pure-Java and pure-JavaScript implementations + Peer-to-peer and brokered messaging + Secure communication via SSL and SASL Universal - Proton is designed to scale both up and down. Equally suitable for simple clients or high-powered servers, it can be deployed in simple peer-to-peer configurations or as part of a global federated messaging network. Embeddable - Proton is carefully written to be portable and cross platform. It has minimal dependencies, and it is architected to be usable with any threading model, as well as with non-threaded applications. These features make it uniquely suited for embedding messaging capabilities into existing software. Standard - Built around the AMQP 1.0 messaging standard, Proton is not only ideal for building out your own messaging applications but also for connecting them to the broader ecosystem of AMQP 1.0-based messaging applications. Getting Started --------------- See the included INSTALL file for build and install instructions and the DEVELOPERS file for information on how to modify and test the library code itself. Please see http://qpid.apache.org/proton for a more info. qpid-proton-0.14.0/TODO0000644000175000017500000000044212770711153014016 0ustar danieldanielQpid Proton TODO List ============================================================================== Beyond this simple laundry list, you can find the list of bugs and enhancements to be fixed by going to the Apache Proton JIRA instance: http://issues.apache.org/jira/browser/PROTON qpid-proton-0.14.0/bin/0000755000175000017500000000000012770711153014076 5ustar danieldanielqpid-proton-0.14.0/bin/export.sh0000755000175000017500000000374112770711153015763 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # export.sh - Create a release archive. set -e trap "cleanup" 0 1 2 3 9 11 13 15 ME=$(basename ${0}) SRC=$(dirname $(dirname $(readlink -f $0))) usage() { echo echo "Usage: ${ME} [DIR] [TAG]" exit 1 } cleanup() { trap - 0 1 2 3 9 11 13 15 echo [ ${WORKDIR} ] && [ -d ${WORKDIR} ] && rm -rf ${WORKDIR} } DIR=$PWD TAG=$(git describe --tags --always) ## ## Allow overrides to be passed on the cmdline ## if [ $# -gt 2 ]; then usage elif [ $# -ge 1 ]; then DIR=$1 if [ $# -eq 2 ]; then TAG=$2 fi fi # verify the tag exists git rev-list -1 tags/${TAG} -- >/dev/null || usage WORKDIR=$(mktemp -d) ## ## Create the archive ## ( cd ${SRC} MTIME=$(date -d @`git log -1 --pretty=format:%ct tags/${TAG}` '+%Y-%m-%d %H:%M:%S') ARCHIVE=$DIR/qpid-proton-${TAG}.tar.gz VERSION=$(git show tags/${TAG}:version.txt) PREFIX=qpid-proton-${VERSION} [ -d ${WORKDIR} ] || mkdir -p ${WORKDIR} git archive --format=tar --prefix=${PREFIX}/ tags/${TAG} \ | tar -x -C ${WORKDIR} cd ${WORKDIR} tar -c -z \ --owner=root --group=root --numeric-owner \ --mtime="${MTIME}" \ -f ${ARCHIVE} ${PREFIX} echo "${ARCHIVE}" ) qpid-proton-0.14.0/bin/jenkins-proton-c-build.sh0000755000175000017500000000444012770711153020734 0ustar danieldaniel#!/bin/bash -e # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 is the continuous delivery build script executed after a git # extract by the Jenkins build process located at the following URL: # https://builds.apache.org/view/M-R/view/Qpid/job/Qpid-proton-c/ # CMAKE_FLAGS="-DCMAKE_BUILD_TYPE=DEBUG -DCMAKE_INSTALL_PREFIX=$PWD/build/ship" XMLOUTPUT=../testresults/TEST-protonc.xml echo Arch: `arch` Uname: `uname -a` lsb_release: `lsb_release -a` User: `whoami` echo Java home: $JAVA_HOME echo ========================= echo Listing installed packages dpkg -l | \ awk '/^ii (cmake |maven |ruby |python |php |.*jdk |swig[0-9]*)/{print $2, $3}'| \ sort echo ========================= which python || exit 1 which swig || exit 1 # if python-pip is available, install the python tox test tool RUN_TOX=false PIP=$(type -p pip || true) if [ -n $PIP ] && [ -x "$PIP" ]; then ldir=$(python -c 'import site; print("%s" % site.USER_BASE)') PATH="$ldir/bin:$PATH" echo "PATH=$PATH" if [ $VIRTUAL_ENV ]; then pip install -U tox else pip install --user -U tox fi RUN_TOX=true fi ls rm -rf build testresults >/dev/null 2>&1 mkdir build testresults >/dev/null 2>&1 cd build >/dev/null 2>&1 cmake ${CMAKE_FLAGS} .. cmake --build . --target install echo Running tests $RUN_TOX && ctest -V -R 'python-tox-test' source config.sh # proton-c tests via python python ../tests/python/proton-test --xml=${XMLOUTPUT} # proton-c native c-* tests ctest -V -R '^c-*' # proton-j tests via jython which mvn && ctest -V -R proton-java echo 'Build completed' qpid-proton-0.14.0/bin/release.sh0000755000175000017500000000316512770711153016062 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # release.sh - Creates a release. ME=$(basename ${0}) CURRDIR=$PWD SRC=$(dirname $(dirname $(readlink -f $0))) usage() { echo "Usage: ${ME} VERSION TAG" exit 1 } if [ $# == 2 ]; then VERSION=$1 TAG=$2 else usage fi die() { printf "ERROR: %s\n" "$*" exit 1 } ## ## Create the tag ## ( cd ${SRC} if [ -n "$(git status -uno --porcelain)" ]; then die must release from a clean checkout fi BRANCH=$(git symbolic-ref -q --short HEAD) if [ -n "${BRANCH}" ]; then REMOTE=$(git config branch.${BRANCH}.remote) else REMOTE="origin" fi git checkout --detach && \ bin/version.sh $VERSION && \ git commit -a -m "Release $VERSION" && \ git tag -m "Release $VERSION" $TAG && \ echo "Run 'git push ${REMOTE} ${TAG}' to push the tag upstream." ) qpid-proton-0.14.0/bin/version.sh0000755000175000017500000000245712770711153016132 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # version.sh - Sets the version of the proton source tree to the given # value. ME=$(basename ${0}) usage() { echo "Usage: ${ME} [SRC] VERSION" exit 1 } if [ $# == 2 ]; then SRC=$1 VERSION=$2 elif [ $# == 1 ]; then SRC=$(dirname $(dirname $(readlink -f $0))) VERSION=$1 else usage fi echo ${VERSION} > ${SRC}/version.txt && \ mvn -q org.codehaus.mojo:versions-maven-plugin:1.2:set org.codehaus.mojo:versions-maven-plugin:1.2:commit -DnewVersion="${VERSION}" -f ${SRC}/pom.xml qpid-proton-0.14.0/config.bat.in0000644000175000017500000000500712770711153015672 0ustar danieldanielREM REM Licensed to the Apache Software Foundation (ASF) under one REM or more contributor license agreements. See the NOTICE file REM distributed with this work for additional information REM regarding copyright ownership. The ASF licenses this file REM to you under the Apache License, Version 2.0 (the REM "License"); you may not use this file except in compliance REM with the License. You may obtain a copy of the License at REM REM http://www.apache.org/licenses/LICENSE-2.0 REM REM Unless required by applicable law or agreed to in writing, REM software distributed under the License is distributed on an REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY REM KIND, either express or implied. See the License for the REM specific language governing permissions and limitations REM under the License. REM REM This is a generated file and will be overwritten the next REM time that cmake is run. REM This build may be one of @CMAKE_CONFIGURATION_TYPES@ REM Choose the configuration this script should reference: SET PROTON_BUILD_CONFIGURATION=relwithdebinfo REM PROTON_HOME is the root of the proton checkout REM PROTON_BUILD is where cmake was run set PROTON_HOME=@CMAKE_SOURCE_DIR@ set PROTON_BUILD=@CMAKE_BINARY_DIR@ set PROTON_HOME=%PROTON_HOME:/=\% set PROTON_BUILD=%PROTON_BUILD:/=\% set PROTON_BINDINGS=%PROTON_BUILD%\proton-c\bindings set PROTON_JARS=%PROTON_BUILD%\proton-j\proton-j.jar REM Python & Jython set PYTHON_BINDINGS=%PROTON_BINDINGS%\python set COMMON_PYPATH=%PROTON_HOME%\tests\python;%PROTON_HOME%\proton-c\bindings\python set PYTHONPATH=%COMMON_PYPATH%;%PYTHON_BINDINGS% set JYTHONPATH=%COMMON_PYPATH%;%PROTON_HOME%\proton-j\src\main\resources;%PROTON_JARS% set CLASSPATH=%PROTON_JARS% REM PHP set PHP_BINDINGS=%PROTON_BINDINGS%\php if EXIST %PHP_BINDINGS% ( echo include_path="%PHP_BINDINGS%;%PROTON_HOME%\proton-c\bindings\php" > %PHP_BINDINGS%\php.ini echo extension="%PHP_BINDINGS%\cproton.so" >> %PHP_BINDINGS%\php.ini set PHPRC=%PHP_BINDINGS%\php.ini ) REM Ruby set RUBY_BINDINGS=%PROTON_BINDINGS%\ruby set RUBYLIB=%RUBY_BINDINGS%;%PROTON_HOME%\proton-c\bindings\ruby\lib;%PROTON_HOME%\tests\ruby REM Perl set PERL_BINDINGS=%PROTON_BINDINGS%\perl set PERL5LIB=%PERL5LIB%;%PERL_BINDINGS%;%PROTON_HOME%\proton-c\bindings\perl\lib REM test applications set PATH=%PATH%;%PROTON_BUILD%\tests\tools\apps\c set PATH=%PATH%;%PROTON_HOME%\tests\tools\apps\python set PATH=%PATH%;%PROTON_HOME%\tests\python set PATH=%PATH%;%PROTON_BUILD%\proton-c\%PROTON_BUILD_CONFIGURATION% qpid-proton-0.14.0/design/0000755000175000017500000000000012770711153014577 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/0000755000175000017500000000000012770711153020350 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/README0000644000175000017500000000030712770711153021230 0ustar danieldanielTool to generate a report mapping proton-c functions to proton-j class methods. On Linux, the list of proton-c functions can be generated using generate-c-functions.sh See pom.xml for more details. qpid-proton-0.14.0/design/api-reconciliation/generate-c-functions.sh0000755000175000017500000000247012770711153024732 0ustar danieldaniel#!/bin/sh # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Script to generate a list of proton-c functions for use as input to the api-reconciliation tool. # If you have problems running ctags, note that there are two ctags executables on some Linux # distributions. The one required here is from the exuberant-ctags package # (http://ctags.sourceforge.net), *not* GNU emacs ctags. BASE_DIR=`dirname $0` INCLUDE_DIR=$BASE_DIR/../../proton-c/include/proton OUTPUT_DIR=$BASE_DIR/target mkdir -p $OUTPUT_DIR ctags --c-kinds=p -x $INCLUDE_DIR/*.h | awk '{print $1'} > $OUTPUT_DIR/cfunctions.txt qpid-proton-0.14.0/design/api-reconciliation/pom.xml0000644000175000017500000001017112770711153021665 0ustar danieldaniel 4.0.0 org.apache.qpid proton-api-reconciliation 1.0-SNAPSHOT ${basedir}/../../build/proton-c ${proton-c-build-dir}/bindings/java/proton-jni.jar org.apache.maven.plugins maven-compiler-plugin 1.6 1.6 true true true org.codehaus.mojo exec-maven-plugin 1.2.1 java org.apache.qpid.proton.apireconciliation.Main true org.apache.qpid.proton target/cfunctions.txt org.apache.qpid.proton.ProtonCEquivalent target/apireconciliation.csv org.apache.qpid proton-jni ${project.version} system ${jni-jar} org.apache.qpid proton-api 1.0-SNAPSHOT junit junit 4.10 test org.reflections reflections 0.9.8 commons-lang commons-lang 2.6 commons-io commons-io 2.4 Tool to generate a report mapping proton-c functions to proton-j class methods. Uses proton-jni and proton-api at run-time, so these libraries must be available to Maven, eg in a local Maven repository. Can be run using sensible defaults using "mvn compile exec:java" org.apache apache 12 qpid-proton-0.14.0/design/api-reconciliation/src/0000755000175000017500000000000012770711153021137 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/0000755000175000017500000000000012770711153022063 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/java/0000755000175000017500000000000012770711153023004 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/0000755000175000017500000000000012770711153023573 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/0000755000175000017500000000000012770711153025014 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/0000755000175000017500000000000012770711153025751 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/0000755000175000017500000000000012770711153027272 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153032766 5ustar danieldaniel././@LongLink0000644000000000000000000000020100000000000011574 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReader.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000276212770711153032777 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.util.List; import org.apache.commons.io.FileUtils; public class CFunctionNameListReader { public List readCFunctionNames(String fileContainingFunctionNames) throws IOException { File functionNameFile = new File(fileContainingFunctionNames); if (!functionNameFile.canRead()) { throw new FileNotFoundException("File " + functionNameFile + " cannot be found or is not readable."); } List cFunctionNames = FileUtils.readLines(functionNameFile); return cFunctionNames; } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Joiner.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000665212770711153033001 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.lang.reflect.Method; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor; public class Joiner { private final AnnotationAccessor _annotationAccessor; public Joiner(AnnotationAccessor annotationAccessor) { _annotationAccessor = annotationAccessor; } /** * Does an outer join of the supplied C functions with those named by the * annotations on the Java methods. */ public ReconciliationReport join(List protonCFunctions, Set javaMethods) { ReconciliationReport report = new ReconciliationReport(); Map cFunctionToJavaMethodMap = createOneToOneMappingBetweenCFunctionNameAndJavaMethodMap(javaMethods); Set unannotatedMethods = new HashSet(javaMethods); unannotatedMethods.removeAll(cFunctionToJavaMethodMap.values()); for (Method unannotatedMethod : unannotatedMethods) { report.addRow(null, unannotatedMethod); } for (String protonCFunction : protonCFunctions) { Method javaMethod = cFunctionToJavaMethodMap.remove(protonCFunction); report.addRow(protonCFunction, javaMethod); } // add anything remaining in annotatedNameToMethod to report as Java methods with an unknown annotation for (Method method : cFunctionToJavaMethodMap.values()) { report.addRow(null, method); } return report; } private Map createOneToOneMappingBetweenCFunctionNameAndJavaMethodMap(Set javaMethods) { Map annotatedNameToMethod = new HashMap(); Set functionsWithDuplicateJavaMappings = new HashSet(); for (Method method : javaMethods) { String functionName = _annotationAccessor.getAnnotationValue(method); if (functionName != null) { if (annotatedNameToMethod.containsKey(functionName)) { functionsWithDuplicateJavaMappings.add(functionName); } annotatedNameToMethod.put(functionName, method); } } // Any functions that had duplicate java method names are removed. for (String functionName : functionsWithDuplicateJavaMappings) { annotatedNameToMethod.remove(functionName); } return annotatedNameToMethod; } } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Main.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000434112770711153032772 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.util.List; import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor; import org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriter; public class Main { public static void main(String[] args) throws Exception { if (args.length != 4) { System.err.println("Unexpected number of arguments. Usage:"); System.err.println(" java " + Main.class.getName() + " packageRootName cFunctionFile annotationClassName outputFile"); Runtime.getRuntime().exit(-1); } String packageRootName = args[0]; String cFunctionFile = args[1]; String annotationClassName = args[2]; String outputFile = args[3]; CFunctionNameListReader cFunctionNameListReader = new CFunctionNameListReader(); AnnotationAccessor annotationAccessor = new AnnotationAccessor(annotationClassName); Reconciliation reconciliation = new Reconciliation(annotationAccessor); List cFunctionNames = cFunctionNameListReader.readCFunctionNames(cFunctionFile); ReconciliationReport report = reconciliation.reconcile(cFunctionNames, packageRootName); ReconciliationReportWriter writer = new ReconciliationReportWriter(annotationAccessor); writer.write(outputFile, report); System.err.println("Written : " + outputFile); } } ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/Reconciliation.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000320512770711153032770 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.lang.reflect.Method; import java.util.List; import java.util.Set; import org.apache.qpid.proton.apireconciliation.packagesearcher.PackageSearcher; import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor; public class Reconciliation { private final PackageSearcher _packageSearcher = new PackageSearcher(); private final Joiner _joiner; public Reconciliation(AnnotationAccessor annotationAccessor) { _joiner = new Joiner(annotationAccessor); } public ReconciliationReport reconcile(List protonCFunctions, String packageRootName) { Set javaMethods = _packageSearcher.findMethods(packageRootName); ReconciliationReport report = _joiner.join(protonCFunctions, javaMethods); return report; } } ././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReconciliationReport.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000247512770711153033000 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; public class ReconciliationReport { private List _reportRows = new ArrayList(); public Iterator rowIterator() { return _reportRows.iterator(); } public void addRow(String declaredProtonCFunction, Method javaMethod) { _reportRows.add(new ReportRow(declaredProtonCFunction, javaMethod)); } } ././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/ReportRow.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000477412770711153033004 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.lang.reflect.Method; import org.apache.commons.lang.builder.EqualsBuilder; import org.apache.commons.lang.builder.HashCodeBuilder; import org.apache.commons.lang.builder.ToStringBuilder; public class ReportRow { private final String _declaredProtonCFunction; private final Method _javaMethod; public ReportRow(String declaredProtonCFunction, Method javaMethod) { _declaredProtonCFunction = declaredProtonCFunction; _javaMethod = javaMethod; } public String getCFunction() { return _declaredProtonCFunction; } public Method getJavaMethod() { return _javaMethod; } @Override public int hashCode() { return new HashCodeBuilder().append(_declaredProtonCFunction) .append(_javaMethod) .toHashCode(); } @Override public boolean equals(Object obj) { if (obj == null) { return false; } if (obj == this) { return true; } if (obj.getClass() != getClass()) { return false; } ReportRow rhs = (ReportRow) obj; return new EqualsBuilder() .append(_declaredProtonCFunction, rhs._declaredProtonCFunction) .append(_javaMethod, rhs._javaMethod) .isEquals(); } @Override public String toString() { return new ToStringBuilder(this) .append("_declaredProtonCFunction", _declaredProtonCFunction) .append("_javaMethod", _javaMethod) .toString(); } } ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/packagesearcher/qpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153032766 5ustar danieldaniel././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcher.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000716312770711153032777 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.logging.Logger; import org.reflections.Reflections; import org.reflections.scanners.SubTypesScanner; public class PackageSearcher { private final static Logger LOGGER = Logger.getLogger(PackageSearcher.class.getName()); public Set findMethods(String packageName) { Reflections reflections = new Reflections(packageName, new SubTypesScanner(false)); Set> allInterfaces = getAllApiInterfaces(reflections); Set allImplMethods = new HashSet(); for (Class apiInterface : allInterfaces) { List apiMethodList = Arrays.asList(apiInterface.getMethods()); Set impls = reflections.getSubTypesOf(apiInterface); if (impls.size() == 0) { // In the case where there are no implementations of apiInterface, we add the methods of // apiInterface so they appear on the final report. for (Method apiMethod : apiMethodList) { allImplMethods.add(apiMethod); } } else { for (Object implementingClassObj : impls) { Class implementingClass = (Class) implementingClassObj; LOGGER.fine("Found implementation " + implementingClass.getName() + " for " + apiInterface.getName()); for (Method apiMethod : apiMethodList) { Method implMethod = findImplMethodOfApiMethod(apiMethod, implementingClass); allImplMethods.add(implMethod); } } } } return allImplMethods; } private Method findImplMethodOfApiMethod(Method apiMethod, Class impl) { try { Method implMethod = impl.getMethod(apiMethod.getName(), apiMethod.getParameterTypes()); return implMethod; } catch (Exception e) { // Should not happen throw new IllegalStateException("Could not find implementation of method " + apiMethod + " on the impl. " + impl, e); } } @SuppressWarnings("rawtypes") private Set> getAllApiInterfaces(Reflections reflections) { Set> classes = reflections.getSubTypesOf(Object.class); Set> interfaces = new HashSet>(); for (Class clazz : classes) { if(clazz.isInterface()) { interfaces.add(clazz); } } return interfaces; } } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/qpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153032766 5ustar danieldaniel././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessor.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000612012770711153032767 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.reportwriter; import java.lang.annotation.Annotation; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; public class AnnotationAccessor { private static final String VALUE_METHOD = "value"; private final Class _annotationClass; private final Method _functionNameMethod; @SuppressWarnings("unchecked") public AnnotationAccessor(String annotationClassName) { try { _annotationClass = (Class) Class.forName(annotationClassName); } catch (ClassNotFoundException e) { throw new IllegalArgumentException("Couldn't find annotation class " + annotationClassName, e); } try { _functionNameMethod = _annotationClass.getMethod(VALUE_METHOD); } catch (SecurityException e) { throw new IllegalArgumentException("Couldn't find method " + VALUE_METHOD + " on annotation " + _annotationClass, e); } catch (NoSuchMethodException e) { throw new IllegalArgumentException("Couldn't find method " + VALUE_METHOD + " on annotation " + _annotationClass, e); } } public String getAnnotationValue(Method javaMethod) { Annotation annotation = javaMethod.getAnnotation(_annotationClass); if (javaMethod != null && annotation != null) { return getProtonCFunctionName(annotation); } else { return null; } } private String getProtonCFunctionName(Annotation annotation) { try { return String.valueOf(_functionNameMethod.invoke(annotation)); } catch (IllegalArgumentException e) { throw new RuntimeException("Couldn't invoke method " + _functionNameMethod + " on annotation " + annotation, e); } catch (IllegalAccessException e) { throw new RuntimeException("Couldn't invoke method " + _functionNameMethod + " on annotation " + annotation, e); } catch (InvocationTargetException e) { throw new RuntimeException("Couldn't invoke method " + _functionNameMethod + " on annotation " + annotation, e); } } } ././@LongLink0000644000000000000000000000022100000000000011576 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriter.javaqpid-proton-0.14.0/design/api-reconciliation/src/main/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000555212770711153032777 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.reportwriter; import static java.lang.String.format; import static org.apache.commons.lang.StringUtils.defaultString; import java.io.File; import java.io.IOException; import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.apache.commons.io.FileUtils; import org.apache.qpid.proton.apireconciliation.ReconciliationReport; import org.apache.qpid.proton.apireconciliation.ReportRow; public class ReconciliationReportWriter { private static final String ROW_FORMAT="%s,%s,%s"; private static final String REPORT_TITLE = format(ROW_FORMAT, "C function","Java Method","Java Annotation"); private final AnnotationAccessor _annotationAccessor; public ReconciliationReportWriter(AnnotationAccessor annotationAccessor) { _annotationAccessor = annotationAccessor; } public void write(String outputFile, ReconciliationReport report) throws IOException { File output = new File(outputFile); List reportLines = new ArrayList(); reportLines.add(REPORT_TITLE); Iterator itr = report.rowIterator(); while (itr.hasNext()) { ReportRow row = itr.next(); Method javaMethod = row.getJavaMethod(); String cFunction = defaultString(row.getCFunction()); String fullyQualifiedMethodName = ""; String annotationCFunction = ""; if (javaMethod != null) { fullyQualifiedMethodName = createFullyQualifiedJavaMethodName(javaMethod); annotationCFunction = defaultString(_annotationAccessor.getAnnotationValue(javaMethod)); } reportLines.add(format(ROW_FORMAT, cFunction, fullyQualifiedMethodName, annotationCFunction)); } FileUtils.writeLines(output, reportLines); } private String createFullyQualifiedJavaMethodName(Method javaMethod) { return javaMethod.getDeclaringClass().getName() + "#" + javaMethod.getName(); } } qpid-proton-0.14.0/design/api-reconciliation/src/test/0000755000175000017500000000000012770711153022116 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/java/0000755000175000017500000000000012770711153023037 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/0000755000175000017500000000000012770711153023626 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/0000755000175000017500000000000012770711153025047 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/0000755000175000017500000000000012770711153026004 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/0000755000175000017500000000000012770711153027325 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/CFunctionNameListReaderTest.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000363012770711153033025 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import static org.junit.Assert.*; import java.io.File; import java.util.Arrays; import java.util.List; import org.apache.commons.io.FileUtils; import org.junit.Test; public class CFunctionNameListReaderTest { private CFunctionNameListReader _cFunctionDeclarationReader = new CFunctionNameListReader(); @Test public void testReadFileContainingSingleCFunction() throws Exception { String declarationFile = createTestFileContaining("function1", "function2", "function3"); List functions = _cFunctionDeclarationReader.readCFunctionNames(declarationFile); assertEquals(3, functions.size()); assertEquals("function1", functions.get(0)); assertEquals("function3", functions.get(2)); } private String createTestFileContaining(String... functionNames) throws Exception { File file = File.createTempFile(CFunctionNameListReader.class.getSimpleName(), "txt"); file.deleteOnExit(); FileUtils.writeLines(file, Arrays.asList(functionNames)); return file.getAbsolutePath(); } } ././@LongLink0000644000000000000000000000016400000000000011604 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/JoinerTest.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000001416112770711153033026 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import static java.util.Arrays.asList; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.lang.reflect.Method; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; import org.apache.qpid.proton.apireconciliation.reportwriter.AnnotationAccessor; import org.junit.Before; import org.junit.Test; public class JoinerTest { private static final String C_FUNCTION1 = "cFunction1"; private static final String C_FUNCTION2 = "cFunction2"; private Joiner _joiner; private Method _method1 = null; private Method _method2 = null; private Method _methodSharingFunctionNameAnnotationWithMethod2 = null; private Method _methodWithoutAnnotation; @Before public void setUp() throws Exception { _method1 = getClass().getMethod("javaMethodWithMapping1"); _method2 = getClass().getMethod("javaMethodWithMapping2"); _methodSharingFunctionNameAnnotationWithMethod2 = getClass().getMethod("javaMethodSharingFunctionNameAnnotationWithMethod2"); _methodWithoutAnnotation = getClass().getMethod("javaMethodWithoutAnnotation"); AnnotationAccessor annotationAccessor = new AnnotationAccessor(TestAnnotation.class.getName()); _joiner = new Joiner(annotationAccessor); } @Test public void testSingleRowReport() throws Exception { List protonCFunctions = asList(C_FUNCTION1); Set javaMethods = new HashSet(asList(_method1)); ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods); assertSingleRowEquals(reconciliationReport, C_FUNCTION1, _method1); } @Test public void testCFunctionWithoutCorrespondingAnnotatedJavaMethod() throws Exception { List protonCFunctions = asList("functionX"); Set javaMethods = Collections.emptySet(); ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods); assertSingleRowEquals(reconciliationReport, "functionX", null); } @Test public void testJavaMethodAnnotatedWithUnknownCFunctionName() throws Exception { List protonCFunctions = Collections.emptyList(); Set javaMethods = new HashSet(asList(_method1)); ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods); assertSingleRowEquals(reconciliationReport, null, _method1); } @Test public void testJavaMethodWithoutAnnotation() throws Exception { List protonCFunctions = Collections.emptyList(); Set javaMethods = new HashSet(asList(_methodWithoutAnnotation)); ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods); assertSingleRowEquals(reconciliationReport, null, _methodWithoutAnnotation); } @Test public void testJavaMethodsWithAnnotationToSameFunction() throws Exception { List protonCFunctions = asList(C_FUNCTION2); Set javaMethods = new HashSet(asList(_method2, _methodSharingFunctionNameAnnotationWithMethod2)); ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods); Set rowSet = TestUtils.getReportRowsFrom(reconciliationReport); Set expectedRowSet = new HashSet(asList( new ReportRow(C_FUNCTION2, null), new ReportRow(null, _method2), new ReportRow(null, _methodSharingFunctionNameAnnotationWithMethod2))); assertEquals(expectedRowSet, rowSet); } @Test public void testMultipleRowReport() throws Exception { List protonCFunctions = asList(C_FUNCTION1, C_FUNCTION2); Set javaMethods = new HashSet(asList(_method1, _method2)); ReconciliationReport reconciliationReport = _joiner.join(protonCFunctions, javaMethods); Set rowSet = TestUtils.getReportRowsFrom(reconciliationReport); Set expectedRowSet = new HashSet(asList( new ReportRow(C_FUNCTION1, _method1), new ReportRow(C_FUNCTION2, _method2))); assertEquals(expectedRowSet,rowSet); } private void assertSingleRowEquals(ReconciliationReport reconciliationReport, String expectedCFunctionName, Method expectedJavaMethod) { Iterator rowIterator = reconciliationReport.rowIterator(); ReportRow row = rowIterator.next(); assertReportRowEquals(row, expectedCFunctionName, expectedJavaMethod); assertFalse(rowIterator.hasNext()); } private void assertReportRowEquals(ReportRow row, String expectedCFunctionName, Method expectedMethod) { assertEquals(expectedCFunctionName, row.getCFunction()); assertEquals(expectedMethod, row.getJavaMethod()); } @TestAnnotation(C_FUNCTION1) public void javaMethodWithMapping1() { } @TestAnnotation(C_FUNCTION2) public void javaMethodWithMapping2() { } @TestAnnotation(C_FUNCTION2) public void javaMethodSharingFunctionNameAnnotationWithMethod2() { } public void javaMethodWithoutAnnotation() { } } ././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/ReportRowTest.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000516012770711153033025 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import static org.junit.Assert.*; import java.lang.reflect.Method; import org.junit.Before; import org.junit.Test; public class ReportRowTest { private Method _javaMethod1; private Method _javaMethod2; @Before public void setUp() throws Exception { _javaMethod1 = getClass().getMethod("javaMethod1"); _javaMethod2 = getClass().getMethod("javaMethod2"); } @Test public void testSames() throws Exception { ReportRow reportRow = new ReportRow("cfunction", _javaMethod1); Object other = new Object(); assertTrue(reportRow.equals(reportRow)); assertFalse(reportRow.equals(other)); } @Test public void testEquals() throws Exception { assertTrue(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow("cfunction", _javaMethod1))); assertFalse(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow("cfunction2", _javaMethod1))); assertFalse(new ReportRow("cfunction2", _javaMethod1).equals(new ReportRow("cfunction2", _javaMethod2))); assertFalse(new ReportRow("cfunction", _javaMethod1).equals(null)); } @Test public void testEqualsWithNulls() throws Exception { assertTrue(new ReportRow("cfunction", null).equals(new ReportRow("cfunction", null))); assertTrue(new ReportRow(null, _javaMethod1).equals(new ReportRow(null, _javaMethod1))); assertFalse(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow("cfunction", null))); assertFalse(new ReportRow("cfunction", _javaMethod1).equals(new ReportRow(null, _javaMethod1))); } // Used by reflection by test methods public void javaMethod1() { } // Used by reflection by test methods public void javaMethod2() { } } ././@LongLink0000644000000000000000000000017000000000000011601 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestAnnotation.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000217012770711153033023 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface TestAnnotation { String value(); }././@LongLink0000644000000000000000000000016300000000000011603 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/TestUtils.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000245612770711153033032 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation; import java.util.HashSet; import java.util.Iterator; import java.util.Set; public class TestUtils { public static Set getReportRowsFrom(ReconciliationReport reconciliationReport) { Iterator rowIterator = reconciliationReport.rowIterator(); Set rows = new HashSet(); while (rowIterator.hasNext()) { rows.add(rowIterator.next()); } return rows; } } ././@LongLink0000644000000000000000000000016500000000000011605 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000021500000000000011601 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/PackageSearcherTest.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000660412770711153033031 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher; import static org.junit.Assert.assertEquals; import java.lang.reflect.Method; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls.Impl1; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls.Impl2; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.manyimpls.InterfaceWithManyImpls; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.noimpl.InterfaceWithoutImpl; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.ImplAtTreeTop; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.InterfaceAtTreeTop; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.tree.leaf.ImplAtLeaf; import org.junit.Test; public class PackageSearcherTest { private PackageSearcher _packageSearcher = new PackageSearcher(); @Test public void testFindDescendsPackageTree() throws Exception { String testDataPackage = InterfaceAtTreeTop.class.getPackage().getName(); Set actualMethods = _packageSearcher.findMethods(testDataPackage); assertEquals(2, actualMethods.size()); Set expectedMethods = new HashSet(Arrays.asList( ImplAtTreeTop.class.getMethod("method"), ImplAtLeaf.class.getMethod("method"))); assertEquals(expectedMethods, actualMethods); } @Test public void testZeroImplenentationsOfInterface() throws Exception { String testDataPackage = InterfaceWithoutImpl.class.getPackage().getName(); Method expectedMethod = InterfaceWithoutImpl.class.getMethod("method"); Set actualMethods = _packageSearcher.findMethods(testDataPackage); assertEquals(1, actualMethods.size()); Method actualMethod = actualMethods.iterator().next(); assertEquals(expectedMethod, actualMethod); } @Test public void testManyImplenentationsOfInterface() throws Exception { String testDataPackage = InterfaceWithManyImpls.class.getPackage().getName(); Set actualMethods = _packageSearcher.findMethods(testDataPackage); assertEquals(2, actualMethods.size()); String methodName = "method"; Set expectedMethods = new HashSet(Arrays.asList( Impl1.class.getMethod(methodName), Impl2.class.getMethod(methodName))); assertEquals(expectedMethods, actualMethods); } } ././@LongLink0000644000000000000000000000017600000000000011607 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000021000000000000011574 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000022200000000000011577 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl1.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000174112770711153033026 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.manyimpls; public class Impl1 implements InterfaceWithManyImpls { public void method() { } } ././@LongLink0000644000000000000000000000022200000000000011577 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/Impl2.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000174112770711153033026 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.manyimpls; public class Impl2 implements InterfaceWithManyImpls { public void method() { } } ././@LongLink0000644000000000000000000000024300000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/manyimpls/InterfaceWithManyImpls.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000170112770711153033022 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.manyimpls; public interface InterfaceWithManyImpls { void method(); } ././@LongLink0000644000000000000000000000020500000000000011600 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/noimpl/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000023600000000000011604 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/noimpl/InterfaceWithoutImpl.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000167312770711153033032 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.noimpl; public interface InterfaceWithoutImpl { void method(); } ././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000024300000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/InterfaceInSubPackage.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000171512770711153033027 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.subpackage; public interface InterfaceInSubPackage { void methodWithinSubpackage(); } ././@LongLink0000644000000000000000000000021600000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/impl/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000025600000000000011606 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/subpackage/impl/ImplOfInterfaceInSubPackage.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000261112770711153033023 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.subpackage.impl; import org.apache.qpid.proton.apireconciliation.TestAnnotation; import org.apache.qpid.proton.apireconciliation.packagesearcher.testdata.subpackage.InterfaceInSubPackage; public class ImplOfInterfaceInSubPackage implements InterfaceInSubPackage { public static final String VALUE_WITHIN_SUBPACKAGE = "subpackageFunction"; public static final String METHOD_WITHIN_SUBPACKAGE = "methodWithinSubpackage"; @TestAnnotation(VALUE_WITHIN_SUBPACKAGE) public void methodWithinSubpackage() { } } ././@LongLink0000644000000000000000000000020300000000000011576 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000022500000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/ImplAtTreeTop.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000174012770711153033025 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.tree; public class ImplAtTreeTop implements InterfaceAtTreeTop { public void method() { } } ././@LongLink0000644000000000000000000000023200000000000011600 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/InterfaceAtTreeTop.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000167012770711153033027 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.tree; public interface InterfaceAtTreeTop { void method(); } ././@LongLink0000644000000000000000000000021000000000000011574 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000022700000000000011604 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/ImplAtLeaf.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000173712770711153033033 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.tree.leaf; public class ImplAtLeaf implements InterfaceAtLeaf { public void method() { } } ././@LongLink0000644000000000000000000000023400000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/packagesearcher/testdata/tree/leaf/InterfaceAtLeaf.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000167112770711153033030 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.packagesearcher.testdata.tree.leaf; public interface InterfaceAtLeaf { void method(); } ././@LongLink0000644000000000000000000000016200000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/qpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000755000175000017500000000000012770711153033021 5ustar danieldaniel././@LongLink0000644000000000000000000000021500000000000011601 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/AnnotationAccessorTest.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000440712770711153033030 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.reportwriter; import static org.junit.Assert.*; import java.lang.reflect.Method; import org.apache.qpid.proton.apireconciliation.TestAnnotation; import org.junit.Before; import org.junit.Test; public class AnnotationAccessorTest { private static final String ANNOTATION_VALUE_1 = "value1"; private static final String ANNOTATED_METHOD_NAME = "annotatedMethod"; private static final String UNANNOTATED_METHOD_NAME = "unannotatedMethod"; private Method _annotatedMethod; private Method _unannotatedMethod; private String _annotationClassName; private AnnotationAccessor _annotationAccessor; @Before public void setUp() throws Exception { _annotatedMethod = getClass().getMethod(ANNOTATED_METHOD_NAME); _unannotatedMethod = getClass().getMethod(UNANNOTATED_METHOD_NAME); _annotationClassName = TestAnnotation.class.getName(); _annotationAccessor = new AnnotationAccessor(_annotationClassName); } @Test public void testGetAnnotationValue() { assertEquals(ANNOTATION_VALUE_1, _annotationAccessor.getAnnotationValue(_annotatedMethod)); } @Test public void testGetAnnotationValueWithoutAnnotationReturnsNull() { assertNull(_annotationAccessor.getAnnotationValue(_unannotatedMethod)); } @TestAnnotation(ANNOTATION_VALUE_1) public void annotatedMethod() { } public void unannotatedMethod() { } } ././@LongLink0000644000000000000000000000022500000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/reportwriter/ReconciliationReportWriterTest.javaqpid-proton-0.14.0/design/api-reconciliation/src/test/java/org/apache/qpid/proton/apireconciliation/0000644000175000017500000000711312770711153033025 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.apireconciliation.reportwriter; import static org.junit.Assert.*; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; import org.apache.commons.io.FileUtils; import org.apache.qpid.proton.apireconciliation.ReconciliationReport; import org.apache.qpid.proton.apireconciliation.TestAnnotation; import org.junit.Before; import org.junit.Test; public class ReconciliationReportWriterTest { private ReconciliationReportWriter _writer; private ReconciliationReport _report = new ReconciliationReport(); @Before public void setUp() { _writer = new ReconciliationReportWriter(new AnnotationAccessor(TestAnnotation.class.getName())); } @Test public void testReportWithSingleFullyMappedRow() throws Exception { File expectedReport = getClasspathResource("expectedsingle.csv"); File outputFile = createTemporaryFile(); _report.addRow("function1", getClass().getMethod("methodWithMapping")); _writer.write(outputFile.getAbsolutePath(), _report); assertFilesSame(expectedReport, outputFile); } @Test public void testReportWithManyRowsSomeUnmapped() throws Exception { File expectedReport = getClasspathResource("expectedmany.csv"); File outputFile = createTemporaryFile(); _report.addRow("function1", getClass().getMethod("methodWithMapping")); _report.addRow("function2", getClass().getMethod("anotherMethodWithMapping")); _report.addRow(null, getClass().getMethod("methodWithoutMapping")); _report.addRow("function4", null); _writer.write(outputFile.getAbsolutePath(), _report); assertFilesSame(expectedReport, outputFile); } private File getClasspathResource(String filename) throws URISyntaxException { URL resource = getClass().getResource(filename); assertNotNull("Resource " + filename + " could not be found",resource); return new File(resource.toURI()); } private File createTemporaryFile() throws Exception { File tmpFile = File.createTempFile(getClass().getSimpleName(), "csv"); tmpFile.deleteOnExit(); return tmpFile; } private void assertFilesSame(File expectedReport, File actualReport) throws IOException { assertTrue(expectedReport.canRead()); assertTrue(actualReport.canRead()); assertEquals("Report contents unexpected", FileUtils.readFileToString(expectedReport), FileUtils.readFileToString(actualReport)); } @TestAnnotation("function1") public void methodWithMapping() { } @TestAnnotation("function2") public void anotherMethodWithMapping() { } public void methodWithoutMapping() { } } qpid-proton-0.14.0/design/api-reconciliation/src/test/resources/0000755000175000017500000000000012770711153024130 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/0000755000175000017500000000000012770711153024717 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/0000755000175000017500000000000012770711153026140 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/0000755000175000017500000000000012770711153027075 5ustar danieldanielqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/0000755000175000017500000000000012770711153030416 5ustar danieldaniel././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/qpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconcilia0000755000175000017500000000000012770711153033141 5ustar danieldaniel././@LongLink0000644000000000000000000000016700000000000011607 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/qpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconcilia0000755000175000017500000000000012770711153033141 5ustar danieldaniel././@LongLink0000644000000000000000000000020700000000000011602 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedmany.csvqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconcilia0000644000175000017500000000063412770711153033146 0ustar danieldanielC function,Java Method,Java Annotation function1,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#methodWithMapping,function1 function2,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#anotherMethodWithMapping,function2 ,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#methodWithoutMapping, function4,, ././@LongLink0000644000000000000000000000021100000000000011575 Lustar rootrootqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconciliation/reportwriter/expectedsingle.csvqpid-proton-0.14.0/design/api-reconciliation/src/test/resources/org/apache/qpid/proton/apireconcilia0000644000175000017500000000024212770711153033141 0ustar danieldanielC function,Java Method,Java Annotation function1,org.apache.qpid.proton.apireconciliation.reportwriter.ReconciliationReportWriterTest#methodWithMapping,function1 qpid-proton-0.14.0/design/build.xml0000644000175000017500000000646712770711153016435 0ustar danieldaniel simple example build file Qpid Proton]]> Copyright © 2011 Rafael Schloming All Rights Reserved.]]> qpid-proton-0.14.0/design/proton_objects.dia0000644000175000017500000000543612770711153020320 0ustar danieldaniel‹í]ß“Ú8~Ï_A‘W"ôÓ’3;ÙJ²¹Û­ÊÕÖ]²uSÆcOÙf&s÷·Ÿd30¶ Έª@̈nKn}ú¤î–~ùõÇ"ÜË8ñ£ðzˆd8f~8¿þõõooÄð×w¯~™ùÞ[õo{‹úE˜è«ëámšÞ½@ð˜xiƒÀ_‚DŽÿç7V…ÆÃw¯ƒM3/õôw«o½4ýÉ2•ƒÐ[ÈëáÄ›~ŸÇÑ2œ óR«rÓ(ˆâÁ½\_Ë^ÃñJÌxKÎÙwÞ\Nbé}¯ ÕËuO}'ã¢ØÅ]”øªHúx·S¤BŽ~ß(³*•¨BáüÝë÷ôu~K«/Ö²Ên´RIºðâ¹îêQmä À«Æ`®p!§=µI}u“nÕݪ‹»Uç'7wQœÆžŸîªœDQ ½0ךÆKyºždêÊÄöU«A-¾ùi¸ÿo^SüëçÞV·çÎc¶¿ãn•¨òàÏÒÛ›†š+—þhHú½Ÿø“@–ݽ¦­‰lG|ñédè½þyCkÈ¥U3!™dõ‡‡ùÒŸÉ䀙m—©t»*6>ÔêÅrÇ6LþUa°ÎTÞ£ŒWâ?¬‡éÁê¯gàMSÿþéj£M¢Éä4]UöKê…3/ž Þ >D?†k¢ˆ?»þ ·«X=%LáàNkÝEÏ&…ɱbõwÁ£JødR”«»÷Ây Wò1pÙQõ~…]Õÿ¹z?M£ äâfÅá.Ch§J™‚ Fv«õ!Nѷҟߦղñi²“ÛèᦄïÊûæxmˆGXæWù#Ý0M´2MÔØ4rLš&ÈÅÊ p°C®0ruí‰8MsªãÊT=ÔŒ¼n•+ðÜQª*©V¯à»{‰*Æ…i™Jýýà›·ðƒGug^˜ Iú¨ÑL!QþÓßep/Sêm‚ný;Øé"%ݪµý¢Í”nb¥1Œi¦i{äÜ3½‚°™"ÅKçáB–?N.%”b©(ëuûì–Šc}+G‚ßôÙê“~öô—Á­B§•u¦Q6NÖ½ŠÝ¿ ´&–θ…Ñ#ã£3†ëÑó£ó©Uêéè<‰â™ŒÝ8h…eˆº!ýLd€´@06K8\Ù¦&X“öX)Õd€_>ø"“Ä2n˜€2 m– ô à³0ÚpÌ3¶ÁDLÀ±Là…1Öà&{„:Ú6…ª38ÀaD(1Ì.Ÿ|öÃï–tÁ¸%†1H¨aP{ÎÅ㞣!/ŸühU=™÷X¨ëêì„§¯#x÷×?>+¨{Ÿ$ÑÔ÷ôo7¯ïG¼B ÏáN]§Ág~œ×©ºÍQR])~_hF-žnÙÝÖf'GÝág¬åË õïü©Ÿ>VkAÕdÞt?(ÕR›G”>c/Žõ»©'œ=†I'¡RKØæc˜˜| Sá87´áù¦Žàz¦é¦W 9uOÔ¸©wˆyÍüizb}âôö&kš vZí“Új…ãJÕ®MûÛD¡`ºpç*Dõïjß“·L£8R_6]±ÙCÏo4éZÆ»¶RMÅê¨üP¶¬¢ ¿¯³óÄJ~‹L®Cœ„%N–8Yâd‰Sï‰&Ɖ&ÏÄɢ׬ “Ctç`§FË•,WÚã¯Å• ‹L¨¯ºÛtM›uª;kŸ:"øÔ¹u©¿<—:jœ‚ Yß’–Ÿ»Ó3M=ñ¤[×’i×RÁî¬W©7^t÷<^t„,ÔY¨³PwP-Ô™›Û ÆÉCšMí%î:µ—*È3ŸÙÛ FGMo¡îæËÎwÎ;ß©èÍ“‰àˆ˜L&BYÏ ( ¦gquAMGÓŸ^§cú†ªf¹IqÊ s‘í—Ø7š'šp³};ë¾ApG}ƒÛ¾ñÓ÷ܳþw©LA‘ÅÿëÏ3ÈVP€t½š™|,¦¬JÏ 5Ñ>.¡z >¹§\Š«Ør¥¥û=YªuÕ:G—ÃÝ^Gº¶ÚŠ£¨áöjàÞí§ß«ÓP™$•±ŒÊBMNVÑr€÷a¿âÒwÇBq+91ÂlˆÊ18ËŠuþ90øøÅ{˸kü=® ` À/€kN j€÷G™"›ŸcÃLm˜é%‡™Bl¤é14ë4ÃùÑH)Án¶/¾ZkìuÌiI»Z ‘zlô©>mk[ðÐÒî8”MÕ±Êr¨ çPÈr¨#8”kx·mWo´¯(C®wSî3sÚn­ èX–:,_²|iOf3­µèTHõ!]Eï6NØ¡$‹0ŠT‡¯ 4¿ìË©_c/LôáG6¦×tLï³5Úƒúº;2½ðûxZv2¼ô Ý<¹8GW8Ï^tNö|êV¼‘áì0±"’˜³üŠobßK5¯MT=§rOˆÀ N\ê0ê:\8 ¨BWWªqóIÄž~ÔTôM ÃùþÚ°¦*¶ën 6X„B jã0³@"È„æS.Ö‘lDOQ†&êÓ<ž óã‰C¹‹\cœ&l?[‡•SŸówñŠiÆ—žô(Mœ=o Œ DŸžÒ—]„“¯ÚýÑΙ:Ƀ´» ÷u¾d:ò³âÌe4§qÎa#“‘¢„Ž…;âÚWîâ+ÂòA2¢ŠàsÈ ³œíÊ•ý]Ïßô½œÆ·\LïŠúËŽ%®==ÊÀ¯uæLI¼¢ÔÿhžTö”‡at?8(æY€v~ŠŽ«¯IOVn¿¨'/cKAŒhðl–‡ôvÝ–œgÜ<}Ðí …¢DýþâæmØÉ6ofaŠÜ¦yGdl¥…¦>BSã0j:B&©’ÄŒ^©ùq0ÒñÔ‚¸¸WàôiË4PODIÈRÕüÌ+¡ÿºbS¾LÆc9óS ]¦¡k„,©ê rUDF’ÆÁáÄh`d¶kÖ‘WŸWTäùÿ Å0ä¦Ó?Èþ¸H*N­{ß""“Ô‹SC1‘²ÍEEn*i+ƶ‚Lå™i¤yÈ6Q“N9\¢c¤ôWÈDt==A÷"´%-„Ù<ô9ÙnðY|m¶;¼«3 i–ðØÆo± ¯í&¼VÙ„¬e6²¶‡‘µ„žeÒÆÑ&ñOl’g½›Cwäy»r¥ÞBÃäY®|1\¹«íëo! Ùä6 :Û‡ ¡8rkJ8 jàñ^„š~ ç~(m”©é(Ó-´Lä¬Kþùuà=ÊøÝ«üBý›ÇÞâÝ«ÿÙ ŒÓv¾qpid-proton-0.14.0/design/src/0000755000175000017500000000000012770711153015366 5ustar danieldanielqpid-proton-0.14.0/design/src/proton/0000755000175000017500000000000012770711154016710 5ustar danieldanielqpid-proton-0.14.0/design/src/proton/Accepted.java0000644000175000017500000000162512770711153021266 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Accepted * * @hidden * */ public interface Accepted extends Outcome { } qpid-proton-0.14.0/design/src/proton/Connection.java0000644000175000017500000000354112770711153021654 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; import java.util.Iterator; /** * Connection * * @opt operations * @opt types * * @composed 1 - "0..n" Session * @composed 1 - "0..?" Transport * */ public interface Connection extends Endpoint { /** * transition local state to ACTIVE */ public void open(); /** * transition local state to CLOSED */ public void close(); /** * @return a newly created session */ public Session session(); /** * @return a newly created transport */ public Transport transport(); /** * @return iterator for endpoints matching the specified local and * remote states */ public Iterator endpoints(Endpoint.State local, Endpoint.State remote); /** * @return iterator for incoming link endpoints with pending * transfers */ public Iterator incoming(); /** * @return iterator for unblocked outgoing link endpoints with * offered credits */ public Iterator outgoing(); } qpid-proton-0.14.0/design/src/proton/Delivery.java0000644000175000017500000000304212770711153021334 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Delivery * * @opt operations * @opt types * * @assoc - local 0..1 DeliveryState * @assoc - remote 0..1 DeliveryState * * @todo deliveries need to track important link state (source and * targets) at the point that they were created * */ public interface Delivery { public byte[] getTag(); public Link getLink(); public DeliveryState getLocalState(); public DeliveryState getRemoteState(); public boolean remoteSettled(); public int getMessageFormat(); /** * updates the state of the delivery * * @param state the new delivery state */ public void disposition(DeliveryState state); /** * settle the delivery */ public void settle(); } qpid-proton-0.14.0/design/src/proton/DeliveryBuffer.java0000644000175000017500000000205312770711154022470 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * DeliveryBuffer * * @opt operations * @opt attributes * @opt types * * @composed 1 - "0..n" Delivery * */ public interface DeliveryBuffer { int next = 0; public int getCapacity(); public int getSize(); } qpid-proton-0.14.0/design/src/proton/DeliveryState.java0000644000175000017500000000160112770711154022335 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * DeliveryState * */ public interface DeliveryState { } qpid-proton-0.14.0/design/src/proton/Endpoint.java0000644000175000017500000000533212770711154021336 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Endpoint * * @opt operations * @opt types * * @assoc - local 1 Endpoint.State * @assoc - remote 1 Endpoint.State * @assoc - local 0..1 Endpoint.Error * @assoc - remote 0..1 Endpoint.Error */ public interface Endpoint { /** * Represents the state of a communication endpoint. */ public static final class State { private String name; private State(String name) { this.name = name; } public String toString() { return name; } }; public static final State UNINIT = new State("UNINIT"); public static final State ACTIVE = new State("ACTIVE"); public static final State CLOSED = new State("CLOSED"); /** * Holds information about an endpoint error. */ public static final class Error { private String name; private String description; public Error(String name, String description) { this.name = name; this.description = description; } public Error(String name) { this(name, null); } public String toString() { if (description == null) { return name; } else { return String.format("%s -- %s", name, description); } } } /** * @return the local endpoint state */ public State getLocalState(); /** * @return the remote endpoint state (as last communicated) */ public State getRemoteState(); /** * @return the local endpoint error, or null if there is none */ public Error getLocalError(); /** * @return the remote endpoint error, or null if there is none */ public Error getRemoteError(); /** * free the endpoint and any associated resources */ public void free(); } qpid-proton-0.14.0/design/src/proton/Link.java0000644000175000017500000000324012770711154020447 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; import java.util.Iterator; /** * Link * * @opt operations * @opt types * * @assoc 1 - n Delivery * * @todo make links able to exist independently from * sessions/connections and allow to migrate * */ public interface Link extends Endpoint { /** * transition local state to ACTIVE */ public void attach(); /** * transition local state to CLOSED */ public void detach(); /** * @param tag a tag for the delivery * * @return a Delivery object */ public Delivery delivery(byte[] tag); /** * @return the unsettled deliveries for this link */ public Iterator unsettled(); /** * Advances the current delivery to the next delivery on the link. * * @return the next delivery or null if there is none */ public Delivery next(); } qpid-proton-0.14.0/design/src/proton/Modified.java0000644000175000017500000000162512770711154021277 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Modified * * @hidden * */ public interface Modified extends Outcome { } qpid-proton-0.14.0/design/src/proton/Outcome.java0000644000175000017500000000163112770711154021167 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Outcome * * @hidden * */ public interface Outcome extends DeliveryState { } qpid-proton-0.14.0/design/src/proton/Received.java0000644000175000017500000000163312770711154021304 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Received * * @hidden * */ public interface Received extends DeliveryState { } qpid-proton-0.14.0/design/src/proton/Receiver.java0000644000175000017500000000272412770711154021324 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Receiver * * @opt operations * @opt types * */ public interface Receiver extends Link { /** * issue the specified number of credits */ public void flow(int credits); /** * Receive message data for the current delivery. * * @param bytes the destination array where the message data is written * @param offset the index to begin writing into the array * @param size the maximum number of bytes to write * * @return the number of bytes written or -1 if there is no more * message data for the current delivery */ public int recv(byte[] bytes, int offset, int size); } qpid-proton-0.14.0/design/src/proton/Rejected.java0000644000175000017500000000162512770711154021304 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Rejected * * @hidden * */ public interface Rejected extends Outcome { } qpid-proton-0.14.0/design/src/proton/Released.java0000644000175000017500000000162512770711154021303 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Released * * @hidden * */ public interface Released extends Outcome { } qpid-proton-0.14.0/design/src/proton/Sender.java0000644000175000017500000000251212770711154020773 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Sender * * @opt operations * @opt types * */ public interface Sender extends Link { /** * indicates pending deliveries * * @param credits the number of pending deliveries * @todo is this absolute or cumulative? */ public void offer(int credits); /** * Sends message data for the current delivery. * * @param bytes the message data */ public void send(byte[] bytes); /** * Abort the current delivery. */ public void abort(); } qpid-proton-0.14.0/design/src/proton/Session.java0000644000175000017500000000336212770711154021202 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; import java.util.Iterator; /** * Session * * @opt operations * @opt types * * @composed 1 - "0..n" Link * @composed 1 incoming 1 DeliveryBuffer * @composed 1 outgoing 1 DeliveryBuffer * */ public interface Session extends Endpoint { /** * transition local state to ACTIVE */ public void begin(); /** * transition local state to CLOSED */ public void end(); /** * @return a newly created outgoing link */ public Sender sender(); /** * @return a newly created incoming link */ public Receiver receiver(); /** * @see Connection#endpoints(Endpoint.State, Endpoint.State) */ public Iterator endpoints(Endpoint.State local, Endpoint.State remote); /** * @see Connection#incoming() */ public Iterator incoming(); /** * @see Connection#outgoing() */ public Iterator outgoing(); } qpid-proton-0.14.0/design/src/proton/Transport.java0000644000175000017500000000277512770711154021562 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 proton; /** * Transport * * @opt operations * @opt types * */ public interface Transport extends Endpoint { /** * @param bytes input bytes for consumption * @param offset the offset within bytes where input begins * @param size the number of bytes available for input * * @return the number of bytes consumed */ public int input(byte[] bytes, int offset, int size); /** * @param bytes array for output bytes * @param offset the offset within bytes where output begins * @param size the number of bytes available for output * * @return the number of bytes written */ public int output(byte[] bytes, int offset, int size); } qpid-proton-0.14.0/design/src/proton/package.html0000644000175000017500000001026012770711154021170 0ustar danieldaniel

Connections are the primary unit of resource management. Sessions and Links are components of connections. When the Connection is freed/discarded, any resources associated with the Sessions and Links are automatically destroyed or discarded as well.

Each of the Connection, Session, and Link endpoints share a common state model. Note that although this follows the same pattern as the protocol state model for open/close, begin/end, and attach/detach, this does not necessarily correspond one to one to the protocol state model for endpoints. For example the engine implementation may detach/reattach a link endpoint without visibly changing the external state.

The state of each endpoint is divided into two parts, one reflecting the state of the local endpoint, and the other reflecting the state of the remote endpoint as last communicated.

     LOCAL:
       UNINIT
       ACTIVE
       CLOSED

     REMOTE:
       UNINIT
       ACTIVE
       CLOSED
    

In total there are 9 possible states:

     LOCAL             REMOTE             Example
     -------------------------------------------------------------------------
     UNINIT            UNINIT             A newly created connection.

     UNINIT            ACTIVE             A remotely initiated connection
                                          prior to full establishment.

     UNINIT            CLOSED             A remotely initiated connection that
                                          has been closed prior to full
                                          establishment.

     ACTIVE            UNINIT             A locally initiated connection prior
                                          to full establishment.

     ACTIVE            ACTIVE             A fully established connection.

     ACTIVE            CLOSED             A remotely terminated connection.

     CLOSED            UNINIT             A locally initiated connection that
                                          has been closed prior to full
                                          establishment.

     CLOSED            ACTIVE             A locally terminated connection.

     CLOSED            CLOSED             A fully terminated connection.
  

Additionally each endpoint has an error slot which may be filled with additional information regarding error conditions, e.g. why the remote endpoint was transitioned to CLOSED.

Questions:

  • The transfer buffer class may not necessarily be explicitly part of the external interface, e.g. it could be absorbed into the session interface.
  • how do we confirm acheiving active/active without iterating over all active/active endpoints?
    • add an ignore/interest flag as part of generic endpoint state?
    • add pending state to local state?
  • what are credits exactly?
    • how does synchronous get work?
      • implies credit unit needs to be messages?
    • credits may not correspond exactly with on-the-wire credits due to local buffering
  • how would 0-x impls work given that we're passing bytes directly to send?
    • have a generic property get/set API?
      • this could address per transfer flags as well
  • how do large messages work?
    • does send need a done flag for multiple transfers?
  • how does resume work?
  • how does abort work?
  • how do we send settled?
    • just call settle on the returned transfer, the engine MUST optimize
  • how do we deal with send and receive modes on individual transfers?
    • could just twiddle the link ones and set them on the transfer frame if they differ from what they were when the attach was made
qpid-proton-0.14.0/docs/0000755000175000017500000000000012770711154014257 5ustar danieldanielqpid-proton-0.14.0/docs/markdown/0000755000175000017500000000000012770711154016101 5ustar danieldanielqpid-proton-0.14.0/docs/markdown/engine/0000755000175000017500000000000012770711154017346 5ustar danieldanielqpid-proton-0.14.0/docs/markdown/engine/engine.md0000644000175000017500000000627212770711154021144 0ustar danieldanielProton's Engine is a stateful component with a low-level API that allows an application to communicate using AMQP. This document gives a high level overview of the Engine's design, intended to be read by application developers intending to use it. The Engine is built around the concept of a protocol engine. The idea behind a protocol engine is to capture all the complex details of implementing a given protocol in a way that is as decoupled as possible from OS details such as I/O and threading models. The result is a highly portable and easily embedded component that provides a full protocol implementation. The Engine API -------------- The Engine contains in-memory representations of AMQP entities such as Connection, Session and Delivery. These are manipulated via its API, which consists of two main parts. - The *control and query API*, commonly referred to as *The Top Half*, which offers functions to directly create, modify and query the Connections, Sessions etc. - The *transport API*, commonly referred to as *The Bottom Half*, which contains a small set of functions to operate on the AMQP entities therein by accepting binary AMQP input and producing binary AMQP output. The Engine's transport layer can be thought of as transforming a *queue of bytes*, therefore the API is expressed in terms of input appended to the *tail* and output fetched from the *head*. Typical Engine usage -------------------- The diagram below shows how the Engine is typically used by an application. The socket's remote peer is serviced by another AMQP application, which may (or may not) use Proton.
| Engine        |
                              | business    |          | "Top Half"    |
                              | logic       |          | Control and   |
                              |             |<---------| query API     |
                              |             |          |               |
                              |             |          +---------------+
                              |             |                 |
     +-------------+          +-------------+          +---------------+
     |             |  Input   |             |  Tail    | Engine        |
     |             |--------->|             |--------->| "Bottom half" |
     |   Socket    |          | Application |          | Transport API |
     |             |<---------| I/O layer   |<---------|               |
     |             |  Output  |             |  Head    |               |
     +-------------+          +-------------+          +---------------+
]]>
For maximum flexibility, the Engine is not multi-threaded. It is therefore typical for an application thread to loop continuously, repeatedly calling the Top Half and Bottom Half functions. Implementations --------------- Implementations of the Engine currently exist in C and Java. Bindings exist from several languages (e.g. Ruby, Python, Java Native Interface) to the C Engine. For more information see the documentation in the code. qpid-proton-0.14.0/docs/markdown/index.md0000644000175000017500000000143012770711154017530 0ustar danieldaniel Proton is a library for speaking AMQP, including: - The AMQP [Messenger API](messenger/index.html), a simple but powerful interface to send and receive messages over AMQP. - The [AMQP Protocol Engine](engine/engine.html), a succinct encapsulation of the full AMQP protocol machinery. Proton is designed for maximum embeddability: - minimal dependencies - minimal assumptions about application threading model Proton is designed to scale up and down: - transparently supports both simple peer to peer messaging and complex globally federated topologies Proton is multi-lingual: - Proton-C - a C implementation with lanuage bindings in Python, Php, Perl, Ruby, and Java (via JNI). - Proton-J - a pure Java implementation Please see http://qpid.apache.org/proton for a more info. qpid-proton-0.14.0/docs/markdown/messenger/0000755000175000017500000000000012770711154020071 5ustar danieldanielqpid-proton-0.14.0/docs/markdown/messenger/addressing-and-routing.md0000644000175000017500000001244112770711154024765 0ustar danieldaniel Messenger Addressing and Routing ================================================= Addressing ------------------------- An address has the following form: [ amqp[s]:// ] [user[:password]@] domain [/[name]] Where domain can be one of: host | host:port | ip | ip:port | name The following are valid examples of addresses: * example.org * example.org:1234 * amqp://example.org * amqps://example.org * example.org/incoming * amqps://example.org/outgoing * amqps://fred:trustno1@example.org * 127.0.0.1:1234 * amqps://127.0.0.1:1234 The "/name" part of the address, that optionally follows the domain, is not used by the Messenger library. For example, if a receiver subscribes to amqp://~0.0.0.0:5678 Then it will receive messages sent to amqp://~0.0.0.0:5678 as well as amqp://~0.0.0.0:5678/foo Likewise, if the receiver subscribes to amqp://~0.0.0.0:5678/foo it will receive messages addressed to amqp://~0.0.0.0:5678/foo amqp://~0.0.0.0:5678 and amqp://~0.0.0.0:5678/bar
Routing ------------------------------ ### Pattern Matching, Address Translation, and Message Routing ### The Messenger library provides message routing capability with an address translation table. Each entry in the table consists of a *pattern* and a *translation*. You store a new route entry in the table with the call: pn_messenger_route(messenger, pattern, translation); The address of each outgoing message is compared to the table's patterns until the first matching pattern is found, or until all patterns have failed to match. If no pattern matches, then Messenger will send (or attempt to send) your message with the address as given. If a pattern does match your outgoing message's address, then Messenger will create a temporary address by transforming your message's address. Your message will be sent to the transformed address, but **(note!)** the address on your outgoing message will not be changed. The receiver will see the original, not the transformed address.
### Two Translation Mechanisms ### Messenger uses two mechanisms to translate addresses. The first is simple string substitution. pattern: COLOSSUS translation: amqp://0.0.0.0:6666 input addr: COLOSSUS result: amqp://0.0.0.0:6666 The second mechanism is wildcard/variable substitution. A wildcard in the pattern matches all or part of your input address. The part of your input address that matched the wildcard is stored. The matched value is then inserted into your translated address in place of numbered variables: $1, $2, and so on, up to a maximum of 64. There are two wildcards: * and % . The rules for matching are: * matches anything % matches anything but a / other characters match themselves the whole input addr must be matched Examples of wildcard matching: pattern: /%/%/% translation: $1x$2x$3 input addr: /foo/bar/baz result: fooxbarxbaz pattern: * translation: $1 inout addr: /foo/bar/baz result: /foo/bar/baz pattern: /* translation: $1 input addr: /foo/bar/baz result: foo/bar/baz pattern: /*baz translation: $1 input addr: /foo/bar/baz result: foo/bar/ pattern: /%baz translation: $1 input addr: /foo/bar/baz result: FAIL pattern: /%/baz translation: $1 input addr: /foo/bar/baz result: FAIL pattern: /%/%/baz translation: $1 input addr: /foo/bar/baz result: foo pattern: /*/baz translation: $1 input addr: /foo/bar/baz result: foo/bar Examples of route translation usage: pattern: foo translation: amqp://foo.com explanation: Any message sent to "foo" will be routed to "amqp://foo.com" pattern: bar/* translation: amqp://bar.com/$1 explanation: Any message sent to bar/ will be routed to the corresponding path within the amqp://bar.com domain. pattern: amqp:* translation: amqps:$1 explanation: Route all messages over TLS. pattern: amqp://foo.com/* translation: amqp://user:password@foo.com/$1 explanation: Supply credentials for foo.com. pattern: amqp://* translation: amqp://user:password@$1 explanation: Supply credentials for all domains. pattern: amqp://%/* translation: amqp://user:password@proxy/$1/$2 explanation: Route all addresses through a single proxy while preserving the original destination. pattern: * translation: amqp://user:password@broker/$1 explanation: Route any address through a single broker.
### First Match Wins ### If you create multiple routing rules, each new rule is appended to your Messenger's list. At send-time, Messenger looks down the list, and the first rule that matches your outgoing message's address wins. Thus, when creating your routing rules, you should create them in order of most specific first, most general last. qpid-proton-0.14.0/docs/markdown/messenger/index.md0000644000175000017500000000126412770711154021525 0ustar danieldanielProton Messenger Documentation ========================================== Proton Messenger is a high-level API that lets you build simple but powerful messaging systems. - Use the [Linux Quick Start](quick-start-linux.html) to download, build, and run your first Messenger example in two minutes. - Examples and explanations of Messenger's [Sending and Receiving](sending-and-receiving.html) capabilities. - Use [Message Disposition](message-disposition.html) functionality to create reliable messaging systems. - Messenger's [Addressing and Routing](addressing-and-routing.html) capabilities allow you to separate application code from installation-specific configuration information. qpid-proton-0.14.0/docs/markdown/messenger/message-disposition.md0000644000175000017500000001270712770711154024410 0ustar danieldanielMessage Disposition =============================== Messenger disposition operations allow a receiver to accept or reject specific messages, or ranges of messages. Senders can then detect the disposition of their messages. Message States --------------------------- Messages have one of four different states: `PN_STATUS_UNKNOWN` `PN_STATUS_PENDING` `PN_STATUS_ACCEPTED` `PN_STATUS_REJECTED`
Windows and Trackers ----------------------------
Messenger does not track the disposition of every message that it sends or receives. To set (or get) the disposition of a message, that message must be within your incoming (or outgoing) window. ( I will use the incoming direction as the example. The outgoing direction works similarly. ) When you call pn_messenger_set_incoming_window(messenger, window_size); you have only declared the window size. The window is not yet created. The window will be created when you issue your first call to pn_messenger_get(messenger, msg); And the window will be further populated only by further calls to pn_messenger_get(). ### Receiving ### To explicitly set or get message dispositions, your messenger must set a positive size for its incoming window: pn_messenger_set_incoming_window(messenger, N); You can implicity accept messages by simply letting enough new messages arrive. As older messages pass beyond the threshold of your incoming window size, they will be automatically accepted. Thus, if you want to automatically accept all messages as they arrive, you can set your incoming window size to 0. To exercise *explicit* control over particular messages or ranges of messages, the receiver can use trackers. The call pn_messenger_incoming_tracker(messenger); will return a tracker for the message most recently returned by a call to pn_messenger_get(messenger, message); With a message that is being tracked, the messenger can accept (or reject) that individual message: pn_messenger_accept(messenger, tracker, 0); pn_messenger_reject(messenger, tracker, 0); Or it can accept (or reject) the tracked message as well as all older messages back to the limit of the incoming window: pn_messenger_accept(messenger, tracker, PN_CUMULATIVE); pn_messenger_reject(messenger, tracker, PN_CUMULATIVE); Once a message is accepted or rejected, its status can no longer be changed, even if you have a separate tracker associated with it.
###When to Accept### Although you *can* accept messages implicitly by letting them fall off the edge of your incoming window, you *shouldn't*. Message disposition is an important form of communication to the sender. The best practice is to let the sender know your response, by explicit acceptance or rejection, as soon as you can. Implicitly accepting messages by allowing them to fall off the edge of the incoming window could delay your response to the sender for an unpredictable amount of time. A nonzero window size places a limit on how much state your Messenger needs to track.
###Accepting by Accident#### If you allow a message to "fall off the edge" of your incoming window before you have explicitly accepted or rejected it, then it will be accepted automatically. But since your incoming window is only filled by calls to pn_messenger_get(messenger, msg); messages cannot be forced to fall over the edge by simply receiving more messages. Messages will not be forced over the edge of the incoming window unless you make too many calls to `pn_messenger_get()` without explicitly accepting or rejecting the messages. Your application should accept or reject each message as soon as practical after getting and processing it.

### Sending ### A sender can learn how an individual message has been received if it has a positive outgoing window size: pn_messenger_set_outgoing_window(messenger, N); and if a tracker has been associated with that message in question. This call: pn_messenger_outgoing_tracker(messenger); will return a tracker for the message most recently given to: pn_messenger_put(messenger, message); To later find the status of the individual tracked message, you can call: pn_messenger_status(messenger, tracker); The returned value will be one of * `PN_STATUS_ACCEPTED` * `PN_STATUS_REJECTED` , or * `PN_STATUS_PENDING` - If the receiver has not disposed the message yet. If either the sender or the receiver simply declares the message (or range of messages) to be settled, with one of these calls: pn_messenger_settle(messenger, tracker, 0); pn_messenger_settle(messenger, tracker, PN_CUMULATIVE); then the sender will see `PN_STATUS_PENDING` as the status of any settled messages.
### Message Rejection ### If a message is rejected by the receiver, it does not mean that the message was malformed. Malformed messages cannot be sent. Even messages with no content are valid messages. Rejection by a receiver should be understood as the receiver saying "I don't want this." or possibly "I don't want this *yet*." depending on your application. The sender could decide to try sending the same message again later, or to send the message to another receiver, or to discard it. The AMQP 1.0 specification permits a distinction between *rejecting* the message, and *releasing* the message, but the Proton library does not expose the *releasing* disposition. qpid-proton-0.14.0/docs/markdown/messenger/quick-start-linux.md0000644000175000017500000000321112770711154024014 0ustar danieldanielLinux Proton Messenger Quick Start ============================================== On a Linux system, these instructions take you from zero to running your first example code. You will need root privileges for one of the commands. Prerequisite Packages --------------------------------- For a minimum build, you will need packages installed on your box for : subversion gcc cmake libuuid-devel Quick Start Commands --------------------------- svn co http://svn.apache.org/repos/asf/qpid/proton/trunk proton cd ./proton mkdir ./build cd ./build cmake .. make all # Become root and go to your build dir. make install # Stop being root. # Now let's see if it works. cd ./proton-c/examples/messenger/c ./recv & ./send # You're done ! ( Kill that recv process. ) # The output you should see: Address: amqp://0.0.0.0 Subject: (no subject) Content: "Hello World!" Notes ---------------------------- 1. If you will be editing and checking in code from this tree, replace the "svn co" line with this: svn co https://svn.apache.org/repos/asf/qpid/proton/trunk You must check out through https, or you will not be able to check in code changes from your tree. 2. The recv application in the example defaults to the same port as the qpid demon. If you happen to have that demon running, and using the default port, the recv app above will fail. 3. If you don't have root privileges, you can still do the "make install" step by setting a non-standard prefix, thus: cmake -DCMAKE_INSTALL_PREFIX=/my/path .. qpid-proton-0.14.0/docs/markdown/messenger/sending-and-receiving.md0000644000175000017500000000640212770711154024555 0ustar danieldanielSending and Receiving Messages ======================================================= The Proton Messenger API provides a mixture of synchronous and asynchronous operations to give you flexibility in deciding when you application should block waiting for I/O, and when it should not. When sending messages, you can: * send a message immediately, * enqueue a message to be sent later, * block until all enqueued messages are sent, * send enqueued messages until a timeout occurs, or * send all messages that can be sent without blocking. When receiving messages, you can: * receive messages that can be received without blocking, * block until at least one message is received, * receive no more than a fixed number of messages. Functions ------------------------------ * `pn_messenger_put(messenger)` Stage message for later transmission, and possibly transmit any messages currently staged that are not blocked. This function will not block. * `pn_messenger_send(messenger)` If messenger timeout is negative (initial default), block until all staged messages have been sent. If messenger timeout is 0, send all messages that can be sent without blocking. If messenger timeout is positive, send all messages that can be sent until timeout expires. *note: If there are any messages that can be received when `pn_messenger_send()` is called, they will be received.* * `pn_messenger_get(messenger, msg)` Dequeue the head of the incoming message queue to your application. This call does not block. * `pn_messenger_recv(messenger)` If messenger timeout is negative(initial default), block until at least one message is received. If timeout is 0, receive whatever messages are available, but do not block. If timeout is positive, receive available messages until timeout expires. *note: If there are any unblocked outgoing messages, they will be sent during this call.* Examples ------------------------------ * send a message immediately pn_messenger_put(messenger, msg); pn_messenger_send(messenger); * enqueue a message to be sent later pn_messenger_put(messenger, msg); *note: The message will be sent whenever it is not blocked and the Messenger code has other I/O work to be done.* * block until all enqueued messages are sent pn_messenger_set_timeout(messenger, -1); pn_messenger_send(messenger); *note: A negative timeout means 'forever'. That is the initial default for a messenger.* * send enqueued messages until a timeout occurs pn_messenger_set_timeout(messenger, 100); /* 100 msec */ pn_messenger_send(messenger); * send all messages that can be sent without blocking pn_messenger_set_timeout(messenger, 0); pn_messenger_send(messenger); * receive messages that can be received without blocking pn_messenger_set_timeout(messenger, 0); pn_messenger_recv(messenger, -1); * block until at least one message is received pn_messenger_set_timeout(messenger, -1); pn_messenger_recv(messenger, -1); *note: -1 is initial messenger default.* * receive no more than a fixed number of messages pn_messenger_recv(messenger, 10); qpid-proton-0.14.0/docs/markdown/memory_management.md0000644000175000017500000001664512770711154022143 0ustar danieldanielProton memory mangement ======================= Proton is a collection of libraries in different programming langauges. Some of the libraries (e.g. C and Java) are written directly in those langauges. Some (e.g. python and ruby) are "bindings", native libraries that that internally use the C library. All the libraries provide a "native" memory management experience, you don't need to know anything about C or the proton C library to use them. If you only program in java, python, ruby or a similar garbage-collected language then you may be wondering "what is *memory management*?" Don't worry, the proton library takes care of it. However, as usual, you are responsible for some non-memory *resource* management. For example if you fail to `close()` a proton connection there won't be memory leaks but the remote end will get a rude "connection failed" error instead of an orderly connection close. If you are a C programmer, you are probably rolling your eyes and wondering why the kids these days expect their memory to be managed for them. Don't worry, the C API offers the standard C experience: you must call `pn_X_free` on a `pn_X_t*` when the time is right and you must know when a `pn_X_t*` can become invalid as a side effect of some other call. Read the doc, learn the rules and get it right. You are a C programmer! If you are a modern C++11 programmer and always use `shared_ptr` and `unique_ptr` to write leak-safe code, then the C++ binding is leak-safe. If you are stuck on C++03, the binding supports `boost::shared_ptr` and `boost::intrusive_ptr`. If you cannot even use boost, the binding provides a simple (type safe, intrusive) smart pointer of its own which can help you. If you are a Go programmer, you know that Go takes care of *Go-allocated* memory but you are responsible other resource cleanup, e.g. closing connections. Go does not have object-scoped cleanup (or indeed objects) but as a crafty Go programmer you know that function-scoped cleanup is all you really need, and `defer` is your friend. The Go binding internally starts goroutines and allocates memory that is not tracked by Go, so proper cleanup is important (but you knew that.) The role of reference counts ---------------------------- Internally, the proton C library uses reference counting, and you can *optionally* use it in your code. You should choose *either* reference counting *or* `pn_X_free` in your code, *not both*. It might work, but it is the sort of Bad Idea that might break your code in the future and will hurt your head in the present. `pn_X_free` is all you really need to write an AMQP application in straight C. However, proton is designed to be embedded and integrated. If you are integrating proton with a new programming language, or some other kind of framework, reference counts may be useful. If your integration target has some form of automatic clean-up that you can hook into (reference-counted pointers, finalizers, destructors or the like) then reference counts may help (e.g. python, ruby and C++ bindings all use them). As a counter-example the Go language is garbage collected, and has finalizers, but does not use reference counts. Go garbage collection is scheduled around memory use, so the timing may not be suitable for other resources. The Go binding does not use proton reference counts, it simply calls `pn_X_free` as part of resource cleanup (e.g. during Connection.Close()) or via finalizers as a fail-safe if resources are not cleaned up properly by the application. If you are mixing your own C code with code using a reference-counted proton binding (e.g. C++ or python) then you may need to at least be aware of reference counting. You can even use reference counts in plain C code if you find that helpful. I don't see how it would be but you never know. The reference counting rules ---------------------------- The proton C API has standard reference counting rules (but see [1] below) - A pointer *returned* by a `pn_` function is either *borrowed* by the caller, or the caller *owns* a reference (the API doc should say which) - The owner of a reference must call `pn_decref()` exactly once to release it. - To keep a borrowed pointer, call `pn_incref()`. This adds a new reference, which you now own. - A pointer *passed* to a `pn_` function has no change of ownership. If you owned a reference you still do, if you didn't you still don't. - An object is never freed while there are still references to it. - An object is freed when all references to it are released. A *borrowed* pointer is valid within some scope (typically the scope of an event handling function) but beyond that scope you cannot assume it is valid unless you make a new reference with `pn_incref`. The API documentation for the function that returned the pointer should tell you what the scope is. There are "container" relationships in proton: e.g. a connection contains sessions, a session contains links. Containers hold a reference to their contents. Freeing a container *releases* that reference. For example freeing a connection releases its sessions. If you don't use reference counts, then freeing a container *frees* the contents in traditional C style. However if you add a reference to a contained object it will *not* be freed till you release your reference, even if all references to container are released [1]. This is useful for bindings to langauges with "finalizers" or "destructors". You can use reference counts to "pin" proton C objects in memory for as long as any binding object needs them. For example: if you call `pn_message()` then you *own* a reference to the newly-created `pn_message_t` and you must call `pn_decref` when you are done [2]. If you call `pn_event_link()` in an event handler then you get a *borrowed* reference to the link. You can use it in the scope of the event handler, but if you want to save it for later you must call `pn_incref` to add a reference and of course call `pn_decref` when you are done with that reference. You should treat `pn_decref` *exactly* like freeing the object: the pointer is dead to you, you must never even look at it again. *Never* write code that assumes that "something else" still has a reference after you have released your own. *Never* write code that checks the value of the reference count (except for debugging purposes.) If you own a reference you can use the pointer. Once you release your reference, the pointer is dead to you. That's the whole story. The point of reference counts is to break ownership dependencies between different parts of the code so that everything will Just Work provided each part of the code independently obeys the simple rules. If your code makes assumptions about distant refcounts or "peeks" to vary its behavior based on what others are doing, you defeat the purpose of reference counting [1]. [1] *Internally* the proton library plays tricks with reference counts to implement 'weak' pointers and manage circular containment relationships. You do *not* need to understand this to use proton, even if you are writing bindings or doing funky mixed-language development. However if you are working on the implementation of the proton C library itself you may need to learn more, ask on proton@qpid.apache.org. [2] Actually if you call `pn_message()` then you must *either* call `pn_decref()` *or* `pn_message_free()`, definitely not both. It is possible to mix reference couting and 'free' style memory management in the same codebase (`free` is sort-of an alias for `decref`) but it is probably not a good idea. qpid-proton-0.14.0/examples/0000755000175000017500000000000012770711155015146 5ustar danieldanielqpid-proton-0.14.0/examples/c/0000755000175000017500000000000012770711154015367 5ustar danieldanielqpid-proton-0.14.0/examples/c/messenger/0000755000175000017500000000000012770711154017357 5ustar danieldanielqpid-proton-0.14.0/examples/c/messenger/recv-async.c0000644000175000017500000001310212770711154021572 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 is a re-implementation of recv.c using non-blocking/asynchronous calls. #include "proton/message.h" #include "proton/messenger.h" #include "pncompat/misc_funcs.inc" #include #include #include #if EMSCRIPTEN #include #endif pn_message_t * message; pn_messenger_t * messenger; #define check(messenger) \ { \ if(pn_messenger_errno(messenger)) \ { \ die(__FILE__, __LINE__, pn_error_text(pn_messenger_error(messenger))); \ } \ } \ void die(const char *file, int line, const char *message) { fprintf(stderr, "%s:%i: %s\n", file, line, message); exit(1); } void usage(void) { printf("Usage: recv [options] \n"); printf("-c \tPath to the certificate file.\n"); printf("-k \tPath to the private key file.\n"); printf("-p \tPassword for the private key.\n"); printf("\tAn address.\n"); exit(0); } void process(void) { while(pn_messenger_incoming(messenger)) { pn_messenger_get(messenger, message); check(messenger); { pn_tracker_t tracker = pn_messenger_incoming_tracker(messenger); char buffer[1024]; size_t buffsize = sizeof(buffer); const char* subject = pn_message_get_subject(message); pn_data_t* body = pn_message_body(message); pn_data_format(body, buffer, &buffsize); printf("Address: %s\n", pn_message_get_address(message)); printf("Subject: %s\n", subject ? subject : "(no subject)"); printf("Content: %s\n", buffer); pn_messenger_accept(messenger, tracker, 0); } } } #if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler. void pump(int fd, void* userData) { while (pn_messenger_work(messenger, 0) >= 0) { process(); } } void onclose(int fd, void* userData) { process(); } void onerror(int fd, int errno, const char* msg, void* userData) { printf("error callback fd = %d, errno = %d, msg = %s\n", fd, errno, msg); } #endif int main(int argc, char** argv) { char* certificate = NULL; char* privatekey = NULL; char* password = NULL; char* address = (char *) "amqp://~0.0.0.0"; int c; message = pn_message(); messenger = pn_messenger(NULL); pn_messenger_set_blocking(messenger, false); // Needs to be set non-blocking to behave asynchronously. opterr = 0; while((c = getopt(argc, argv, "hc:k:p:")) != -1) { switch(c) { case 'h': usage(); break; case 'c': certificate = optarg; break; case 'k': privatekey = optarg; break; case 'p': password = optarg; break; case '?': if (optopt == 'c' || optopt == 'k' || optopt == 'p') { fprintf(stderr, "Option -%c requires an argument.\n", optopt); } else if(isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); } return 1; default: abort(); } } if (optind < argc) { address = argv[optind]; } /* load the various command line options if they're set */ if(certificate) { pn_messenger_set_certificate(messenger, certificate); } if(privatekey) { pn_messenger_set_private_key(messenger, privatekey); } if(password) { pn_messenger_set_password(messenger, password); } pn_messenger_start(messenger); check(messenger); pn_messenger_subscribe(messenger, address); check(messenger); pn_messenger_recv(messenger, -1); // Set to receive as many messages as messenger can buffer. #if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler. emscripten_set_socket_error_callback(NULL, onerror); emscripten_set_socket_open_callback(NULL, pump); emscripten_set_socket_connection_callback(NULL, pump); emscripten_set_socket_message_callback(NULL, pump); emscripten_set_socket_close_callback(NULL, onclose); #else // For native compiler. while (1) { pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity. process(); } #endif return 0; } qpid-proton-0.14.0/examples/c/messenger/recv.c0000644000175000017500000000766312770711154020476 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "proton/message.h" #include "proton/messenger.h" #include "pncompat/misc_funcs.inc" #include #include #include #define check(messenger) \ { \ if(pn_messenger_errno(messenger)) \ { \ die(__FILE__, __LINE__, pn_error_text(pn_messenger_error(messenger))); \ } \ } \ void die(const char *file, int line, const char *message) { fprintf(stderr, "%s:%i: %s\n", file, line, message); exit(1); } void usage(void) { printf("Usage: recv [options] \n"); printf("-c \tPath to the certificate file.\n"); printf("-k \tPath to the private key file.\n"); printf("-p \tPassword for the private key.\n"); printf("\tAn address.\n"); exit(0); } int main(int argc, char** argv) { char* certificate = NULL; char* privatekey = NULL; char* password = NULL; char* address = (char *) "amqp://~0.0.0.0"; int c; pn_message_t * message; pn_messenger_t * messenger; message = pn_message(); messenger = pn_messenger(NULL); opterr = 0; while((c = getopt(argc, argv, "hc:k:p:")) != -1) { switch(c) { case 'h': usage(); break; case 'c': certificate = optarg; break; case 'k': privatekey = optarg; break; case 'p': password = optarg; break; case '?': if(optopt == 'c' || optopt == 'k' || optopt == 'p') { fprintf(stderr, "Option -%c requires an argument.\n", optopt); } else if(isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); } return 1; default: abort(); } } if (optind < argc) { address = argv[optind]; } /* load the various command line options if they're set */ if(certificate) { pn_messenger_set_certificate(messenger, certificate); } if(privatekey) { pn_messenger_set_private_key(messenger, privatekey); } if(password) { pn_messenger_set_password(messenger, password); } pn_messenger_start(messenger); check(messenger); pn_messenger_subscribe(messenger, address); check(messenger); for(;;) { pn_messenger_recv(messenger, 1024); check(messenger); while(pn_messenger_incoming(messenger)) { pn_messenger_get(messenger, message); check(messenger); { char buffer[1024]; size_t buffsize = sizeof(buffer); const char* subject = pn_message_get_subject(message); pn_data_t *body = pn_message_body(message); pn_data_format(body, buffer, &buffsize); printf("Address: %s\n", pn_message_get_address(message)); printf("Subject: %s\n", subject ? subject : "(no subject)"); printf("Content: %s\n", buffer); } } } return 0; } qpid-proton-0.14.0/examples/c/messenger/send-async.c0000644000175000017500000001170412770711154021572 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 is a re-implementation of send.c using non-blocking/asynchronous calls. #include "proton/message.h" #include "proton/messenger.h" #include "pncompat/misc_funcs.inc" #include #include #include #include #if EMSCRIPTEN #include #endif pn_message_t * message; pn_messenger_t * messenger; pn_tracker_t tracker; int running = 1; #define check(messenger) \ { \ if(pn_messenger_errno(messenger)) \ { \ die(__FILE__, __LINE__, pn_error_text(pn_messenger_error(messenger))); \ } \ } \ void die(const char *file, int line, const char *message) { fprintf(stderr, "%s:%i: %s\n", file, line, message); exit(1); } void usage(void) { printf("Usage: send [-a addr] [message]\n"); printf("-a \tThe target address [amqp[s]://domain[/name]]\n"); printf("message\tA text string to send.\n"); exit(0); } void process(void) { pn_status_t status = pn_messenger_status(messenger, tracker); if (status != PN_STATUS_PENDING) { if (running) { pn_messenger_stop(messenger); running = 0; } } if (pn_messenger_stopped(messenger)) { pn_message_free(message); pn_messenger_free(messenger); message = NULL; messenger = NULL; } } #if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler. void pump(int fd, void* userData) { while (pn_messenger_work(messenger, 0) >= 0) { process(); } } void onclose(int fd, void* userData) { process(); } void onerror(int fd, int errno, const char* msg, void* userData) { printf("error callback fd = %d, errno = %d, msg = %s\n", fd, errno, msg); } #endif int main(int argc, char** argv) { int c; char * address = (char *) "amqp://0.0.0.0"; char * msgtext = (char *) "Hello World!"; pn_data_t* body; opterr = 0; while((c = getopt(argc, argv, "ha:b:c:")) != -1) { switch(c) { case 'a': address = optarg; break; case 'h': usage(); break; case '?': if(optopt == 'a') { fprintf(stderr, "Option -%c requires an argument.\n", optopt); } else if(isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); } return 1; default: abort(); } } if (optind < argc) msgtext = argv[optind]; message = pn_message(); messenger = pn_messenger(NULL); pn_messenger_set_blocking(messenger, false); // Needs to be set non-blocking to behave asynchronously. pn_messenger_set_outgoing_window(messenger, 1024); pn_messenger_start(messenger); pn_message_set_address(message, address); body = pn_message_body(message); pn_data_put_string(body, pn_bytes(strlen(msgtext), msgtext)); pn_messenger_put(messenger, message); check(messenger); tracker = pn_messenger_outgoing_tracker(messenger); #if EMSCRIPTEN // For emscripten C/C++ to JavaScript compiler. emscripten_set_socket_error_callback(NULL, onerror); emscripten_set_socket_open_callback(NULL, pump); emscripten_set_socket_connection_callback(NULL, pump); emscripten_set_socket_message_callback(NULL, pump); emscripten_set_socket_close_callback(NULL, onclose); #else // For native compiler. while (running) { pn_messenger_work(messenger, -1); // Block indefinitely until there has been socket activity. process(); } while (messenger && !pn_messenger_stopped(messenger)) { pn_messenger_work(messenger, 0); process(); } #endif return 0; } qpid-proton-0.14.0/examples/c/messenger/send.c0000644000175000017500000000610012770711154020451 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "proton/message.h" #include "proton/messenger.h" #include "pncompat/misc_funcs.inc" #include #include #include #include #define check(messenger) \ { \ if(pn_messenger_errno(messenger)) \ { \ die(__FILE__, __LINE__, pn_error_text(pn_messenger_error(messenger))); \ } \ } \ void die(const char *file, int line, const char *message) { fprintf(stderr, "%s:%i: %s\n", file, line, message); exit(1); } void usage(void) { printf("Usage: send [-a addr] [message]\n"); printf("-a \tThe target address [amqp[s]://domain[/name]]\n"); printf("message\tA text string to send.\n"); exit(0); } int main(int argc, char** argv) { int c; char * address = (char *) "amqp://0.0.0.0"; char * msgtext = (char *) "Hello World!"; opterr = 0; while((c = getopt(argc, argv, "ha:b:c:")) != -1) { switch(c) { case 'a': address = optarg; break; case 'h': usage(); break; case '?': if(optopt == 'a') { fprintf(stderr, "Option -%c requires an argument.\n", optopt); } else if(isprint(optopt)) { fprintf(stderr, "Unknown option `-%c'.\n", optopt); } else { fprintf(stderr, "Unknown option character `\\x%x'.\n", optopt); } return 1; default: abort(); } } if (optind < argc) msgtext = argv[optind]; { pn_message_t * message; pn_messenger_t * messenger; pn_data_t * body; message = pn_message(); messenger = pn_messenger(NULL); pn_messenger_start(messenger); pn_message_set_address(message, address); body = pn_message_body(message); pn_data_put_string(body, pn_bytes(strlen(msgtext), msgtext)); pn_messenger_put(messenger, message); check(messenger); pn_messenger_send(messenger, -1); check(messenger); pn_messenger_stop(messenger); pn_messenger_free(messenger); pn_message_free(message); } return 0; } qpid-proton-0.14.0/examples/c/messenger/CMakeLists.txt0000644000175000017500000000306312770711154022121 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # find_package(Proton REQUIRED) set (messenger-examples recv.c send.c recv-async.c send-async.c ) set_source_files_properties ( ${messenger-examples} PROPERTIES COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LINK_TIME_OPTIMIZATION}" ) if (BUILD_WITH_CXX) set_source_files_properties ( ${messenger-examples} PROPERTIES LANGUAGE CXX ) endif (BUILD_WITH_CXX) add_executable(recv recv.c) add_executable(send send.c) add_executable(recv-async recv-async.c) add_executable(send-async send-async.c) include_directories(${Proton_INCLUDE_DIRS}) target_link_libraries(recv ${Proton_LIBRARIES}) target_link_libraries(send ${Proton_LIBRARIES}) target_link_libraries(recv-async ${Proton_LIBRARIES}) target_link_libraries(send-async ${Proton_LIBRARIES}) qpid-proton-0.14.0/examples/c/CMakeLists.txt0000644000175000017500000000160512770711154020131 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include_directories(${CMAKE_CURRENT_SOURCE_DIR}/include) add_subdirectory(messenger) add_subdirectory(reactor) qpid-proton-0.14.0/examples/c/include/0000755000175000017500000000000012770711154017012 5ustar danieldanielqpid-proton-0.14.0/examples/c/include/pncompat/0000755000175000017500000000000012770711154020633 5ustar danieldanielqpid-proton-0.14.0/examples/c/include/pncompat/internal/0000755000175000017500000000000012770711154022447 5ustar danieldanielqpid-proton-0.14.0/examples/c/include/pncompat/internal/LICENSE0000644000175000017500000000277012770711154023462 0ustar danieldanielFree Getopt Copyright (c)2002-2003 Mark K. Kim All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. * Neither the original author of this software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. qpid-proton-0.14.0/examples/c/include/pncompat/internal/getopt.c0000644000175000017500000001447712770711154024132 0ustar danieldaniel/***************************************************************************** * getopt.c - competent and free getopt library. * $Header: /cvsroot/freegetopt/freegetopt/getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $ * * Copyright (c)2002-2003 Mark K. Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the original author of this software nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #include #include #include #include "getopt.h" static const char* ID = "$Id: getopt.c,v 1.2 2003/10/26 03:10:20 vindaci Exp $"; char* optarg = NULL; int optind = 0; int opterr = 1; int optopt = '?'; static char** prev_argv = NULL; /* Keep a copy of argv and argc to */ static int prev_argc = 0; /* tell if getopt params change */ static int argv_index = 0; /* Option we're checking */ static int argv_index2 = 0; /* Option argument we're checking */ static int opt_offset = 0; /* Index into compounded "-option" */ static int dashdash = 0; /* True if "--" option reached */ static int nonopt = 0; /* How many nonopts we've found */ static void increment_index() { /* Move onto the next option */ if(argv_index < argv_index2) { while(prev_argv[++argv_index] && prev_argv[argv_index][0] != '-' && argv_index < argv_index2+1); } else argv_index++; opt_offset = 1; } /* * Permutes argv[] so that the argument currently being processed is moved * to the end. */ static int permute_argv_once() { /* Movability check */ if(argv_index + nonopt >= prev_argc) return 1; /* Move the current option to the end, bring the others to front */ else { char* tmp = prev_argv[argv_index]; /* Move the data */ memmove(&prev_argv[argv_index], &prev_argv[argv_index+1], sizeof(char**) * (prev_argc - argv_index - 1)); prev_argv[prev_argc - 1] = tmp; nonopt++; return 0; } } int getopt(int argc, char** argv, char* optstr) { int c = 0; /* If we have new argv, reinitialize */ if(prev_argv != argv || prev_argc != argc) { /* Initialize variables */ prev_argv = argv; prev_argc = argc; argv_index = 1; argv_index2 = 1; opt_offset = 1; dashdash = 0; nonopt = 0; } /* Jump point in case we want to ignore the current argv_index */ getopt_top: /* Misc. initializations */ optarg = NULL; /* Dash-dash check */ if(argv[argv_index] && !strcmp(argv[argv_index], "--")) { dashdash = 1; increment_index(); } /* If we're at the end of argv, that's it. */ if(argv[argv_index] == NULL) { c = -1; } /* Are we looking at a string? Single dash is also a string */ else if(dashdash || argv[argv_index][0] != '-' || !strcmp(argv[argv_index], "-")) { /* If we want a string... */ if(optstr[0] == '-') { c = 1; optarg = argv[argv_index]; increment_index(); } /* If we really don't want it (we're in POSIX mode), we're done */ else if(optstr[0] == '+' || getenv("POSIXLY_CORRECT")) { c = -1; /* Everything else is a non-opt argument */ nonopt = argc - argv_index; } /* If we mildly don't want it, then move it back */ else { if(!permute_argv_once()) goto getopt_top; else c = -1; } } /* Otherwise we're looking at an option */ else { char* opt_ptr = NULL; /* Grab the option */ c = argv[argv_index][opt_offset++]; /* Is the option in the optstr? */ if(optstr[0] == '-') opt_ptr = strchr(optstr+1, c); else opt_ptr = strchr(optstr, c); /* Invalid argument */ if(!opt_ptr) { if(opterr) { fprintf(stderr, "%s: invalid option -- %c\n", argv[0], c); } optopt = c; c = '?'; /* Move onto the next option */ increment_index(); } /* Option takes argument */ else if(opt_ptr[1] == ':') { /* ie, -oARGUMENT, -xxxoARGUMENT, etc. */ if(argv[argv_index][opt_offset] != '\0') { optarg = &argv[argv_index][opt_offset]; increment_index(); } /* ie, -o ARGUMENT (only if it's a required argument) */ else if(opt_ptr[2] != ':') { /* One of those "you're not expected to understand this" moment */ if(argv_index2 < argv_index) argv_index2 = argv_index; while(argv[++argv_index2] && argv[argv_index2][0] == '-'); optarg = argv[argv_index2]; /* Don't cross into the non-option argument list */ if(argv_index2 + nonopt >= prev_argc) optarg = NULL; /* Move onto the next option */ increment_index(); } else { /* Move onto the next option */ increment_index(); } /* In case we got no argument for an option with required argument */ if(optarg == NULL && opt_ptr[2] != ':') { optopt = c; c = '?'; if(opterr) { fprintf(stderr,"%s: option requires an argument -- %c\n", argv[0], optopt); } } } /* Option does not take argument */ else { /* Next argv_index */ if(argv[argv_index][opt_offset] == '\0') { increment_index(); } } } /* Calculate optind */ if(c == -1) { optind = argc - nonopt; } else { optind = argv_index; } return c; } /* vim:ts=3 */ qpid-proton-0.14.0/examples/c/include/pncompat/internal/getopt.h0000644000175000017500000000403312770711154024122 0ustar danieldaniel/***************************************************************************** * getopt.h - competent and free getopt library. * $Header: /cvsroot/freegetopt/freegetopt/getopt.h,v 1.2 2003/10/26 03:10:20 vindaci Exp $ * * Copyright (c)2002-2003 Mark K. Kim * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in * the documentation and/or other materials provided with the * distribution. * * * Neither the original author of this software nor the names of its * contributors may be used to endorse or promote products derived * from this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH * DAMAGE. */ #ifndef GETOPT_H_ #define GETOPT_H_ #ifdef __cplusplus extern "C" { #endif extern char* optarg; extern int optind; extern int opterr; extern int optopt; int getopt(int argc, char** argv, char* optstr); #ifdef __cplusplus } #endif #endif /* GETOPT_H_ */ /* vim:ts=3 */ qpid-proton-0.14.0/examples/c/include/pncompat/misc_defs.h0000644000175000017500000000264012770711154022742 0ustar danieldaniel#ifndef PNCOMAPT_MISC_DEFS_H #define PNCOMAPT_MISC_DEFS_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. * */ #if defined(qpid_proton_EXPORTS) #error This include file is not for use in the main proton library #endif /* * Platform neutral definitions. Only intended for use by Proton * examples and test/debug programs. * * This file and any related support files may change or be removed * at any time. */ // getopt() #include #if defined(__IBMC__) # include #elif !defined(_WIN32) || defined (__CYGWIN__) # include #else # include "internal/getopt.h" #endif pn_timestamp_t time_now(void); #endif /* PNCOMPAT_MISC_DEFS_H */ qpid-proton-0.14.0/examples/c/include/pncompat/misc_funcs.inc0000644000175000017500000000410412770711154023456 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 the functions for "misc_defs.h" in the form of * included code, as opposed to a separate library or object * dependency. In the absence of portable "pragma weak" compiler * directives, this provides a simple workaround. * * Usage for a single compilation unit: * * #include "pncompat/misc_funcs.inc" * * Usage for multiple combined compilation units: chose one to include * "pncompat/misc_funcs.inc" as above and in each other unit needing the * definitions use * * #include "pncompat/misc_defs.h" * */ #include "misc_defs.h" #if defined(_WIN32) && ! defined(__CYGWIN__) #include "pncompat/internal/getopt.c" #endif #if defined(_WIN32) && ! defined(__CYGWIN__) #include pn_timestamp_t time_now(void) { FILETIME now; ULARGE_INTEGER t; GetSystemTimeAsFileTime(&now); t.u.HighPart = now.dwHighDateTime; t.u.LowPart = now.dwLowDateTime; // Convert to milliseconds and adjust base epoch return t.QuadPart / 10000 - 11644473600000; } #else #include #include #include #include pn_timestamp_t time_now(void) { struct timeval now; if (gettimeofday(&now, NULL)) {fprintf(stderr, "gettimeofday failed\n"); abort();} return ((pn_timestamp_t)now.tv_sec) * 1000 + (now.tv_usec / 1000); } #endif qpid-proton-0.14.0/examples/c/reactor/0000755000175000017500000000000012770711154017026 5ustar danieldanielqpid-proton-0.14.0/examples/c/reactor/CMakeLists.txt0000644000175000017500000000255212770711154021572 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # find_package(Proton REQUIRED) set (reactor-examples sender.c receiver.c ) set_source_files_properties ( ${reactor-examples} PROPERTIES COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS} ${LINK_TIME_OPTIMIZATION}" ) if (BUILD_WITH_CXX) set_source_files_properties ( ${reactor-examples} PROPERTIES LANGUAGE CXX ) endif (BUILD_WITH_CXX) include_directories(${Proton_INCLUDE_DIRS}) add_executable(sender sender.c) add_executable(receiver receiver.c) target_link_libraries(sender ${Proton_LIBRARIES}) target_link_libraries(receiver ${Proton_LIBRARIES}) qpid-proton-0.14.0/examples/c/reactor/README0000644000175000017500000000166712770711154017720 0ustar danieldanielThese example clients require a broker or similar intermediary that supports the AMQP 1.0 protocol, allows anonymous connections and accepts links to and from a node named 'examples'. ------------------------------------------------------------------ sender.c A simple message sending client. This example sends all messages but the last as pre-settled (no ack required). It then pends waiting for an ack for the last message sent before exiting. Use the '-h' command line option for a list of supported parameters. ------------------------------------------------------------------ receiver.c A simple message consuming client. This example receives messages from a target (default 'examples'). Received messages are acknowledged if they are sent un-settled. The client will try to decode the message payload assuming it has been generated by the sender example. Use the '-h' command line option for a list of supported parameters. qpid-proton-0.14.0/examples/c/reactor/receiver.c0000644000175000017500000002313212770711154020777 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include "pncompat/misc_funcs.inc" #include "proton/reactor.h" #include "proton/message.h" #include "proton/connection.h" #include "proton/session.h" #include "proton/link.h" #include "proton/delivery.h" #include "proton/event.h" #include "proton/handlers.h" #include "proton/transport.h" #include "proton/url.h" static int quiet = 0; // Credit batch if unlimited receive (-c 0) static const int CAPACITY = 100; #define MAX_SIZE 512 // Example application data. This data will be instantiated in the event // handler, and is available during event processing. In this example it // holds configuration and state information. // typedef struct { int count; // # of messages to receive before exiting const char *source; // name of the source node to receive from pn_message_t *message; // holds the received message } app_data_t; // helper to pull pointer to app_data_t instance out of the pn_handler_t // #define GET_APP_DATA(handler) ((app_data_t *)pn_handler_mem(handler)) // Called when reactor exits to clean up app_data // static void delete_handler(pn_handler_t *handler) { app_data_t *d = GET_APP_DATA(handler); if (d->message) { pn_decref(d->message); d->message = NULL; } } /* Process each event posted by the reactor. */ static void event_handler(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) { app_data_t *data = GET_APP_DATA(handler); switch (type) { case PN_CONNECTION_INIT: { // Create and open all the endpoints needed to send a message // pn_connection_t *conn; pn_session_t *ssn; pn_link_t *receiver; conn = pn_event_connection(event); pn_connection_open(conn); ssn = pn_session(conn); pn_session_open(ssn); receiver = pn_receiver(ssn, "MyReceiver"); pn_terminus_set_address(pn_link_source(receiver), data->source); pn_link_open(receiver); // cannot receive without granting credit: pn_link_flow(receiver, data->count ? data->count : CAPACITY); } break; case PN_DELIVERY: { // A message has been received // pn_link_t *link = NULL; pn_delivery_t *dlv = pn_event_delivery(event); if (pn_delivery_readable(dlv) && !pn_delivery_partial(dlv)) { // A full message has arrived if (!quiet) { static char buffer[MAX_SIZE]; ssize_t len; pn_bytes_t bytes; bool found = false; // try to decode the message body if (pn_delivery_pending(dlv) < MAX_SIZE) { // read in the raw data len = pn_link_recv(pn_delivery_link(dlv), buffer, MAX_SIZE); if (len > 0) { // decode it into a proton message pn_message_clear(data->message); if (PN_OK == pn_message_decode(data->message, buffer, len)) { // Assuming the message came from the sender // example, try to parse out a single string from // the payload // pn_data_scan(pn_message_body(data->message), "?S", &found, &bytes); } } } if (found) { fprintf(stdout, "Message: [%.*s]\n", (int)bytes.size, bytes.start); } else { fprintf(stdout, "Message received!\n"); } } link = pn_delivery_link(dlv); if (!pn_delivery_settled(dlv)) { // remote has not settled, so it is tracking the delivery. Ack // it. pn_delivery_update(dlv, PN_ACCEPTED); } // done with the delivery, move to the next and free it pn_link_advance(link); pn_delivery_settle(dlv); // dlv is now freed if (data->count == 0) { // send forever - see if more credit is needed if (pn_link_credit(link) < CAPACITY/2) { // Grant enough credit to bring it up to CAPACITY: pn_link_flow(link, CAPACITY - pn_link_credit(link)); } } else if (--data->count == 0) { // done receiving, close the endpoints pn_session_t *ssn = pn_link_session(link); pn_link_close(link); pn_session_close(ssn); pn_connection_close(pn_session_connection(ssn)); } } } break; case PN_TRANSPORT_ERROR: { // The connection to the peer failed. // pn_transport_t *tport = pn_event_transport(event); pn_condition_t *cond = pn_transport_condition(tport); fprintf(stderr, "Network transport failed!\n"); if (pn_condition_is_set(cond)) { const char *name = pn_condition_get_name(cond); const char *desc = pn_condition_get_description(cond); fprintf(stderr, " Error: %s Description: %s\n", (name) ? name : "", (desc) ? desc : ""); } // pn_reactor_process() will exit with a false return value, stopping // the main loop. } break; default: break; } } static void usage(void) { printf("Usage: receiver \n"); printf("-a \tThe host address [localhost:5672]\n"); printf("-c \t# of messages to receive, 0=receive forever [1]\n"); printf("-s \tSource address [examples]\n"); printf("-i \tContainer name [ReceiveExample]\n"); printf("-q \tQuiet - turn off stdout\n"); exit(1); } int main(int argc, char** argv) { const char *address = "localhost"; const char *container = "ReceiveExample"; int c; pn_reactor_t *reactor = NULL; pn_url_t *url = NULL; pn_connection_t *conn = NULL; /* create a handler for the connection's events. * event_handler will be called for each event. The handler will allocate * a app_data_t instance which can be accessed when the event_handler is * called. */ pn_handler_t *handler = pn_handler_new(event_handler, sizeof(app_data_t), delete_handler); /* set up the application data with defaults */ app_data_t *app_data = GET_APP_DATA(handler); memset(app_data, 0, sizeof(app_data_t)); app_data->count = 1; app_data->source = "examples"; app_data->message = pn_message(); /* Attach the pn_handshaker() handler. This handler deals with endpoint * events from the peer so we don't have to. */ { pn_handler_t *handshaker = pn_handshaker(); pn_handler_add(handler, handshaker); pn_decref(handshaker); } /* command line options */ opterr = 0; while((c = getopt(argc, argv, "i:a:c:s:qh")) != -1) { switch(c) { case 'h': usage(); break; case 'a': address = optarg; break; case 'c': app_data->count = atoi(optarg); if (app_data->count < 0) usage(); break; case 's': app_data->source = optarg; break; case 'i': container = optarg; break; case 'q': quiet = 1; break; default: usage(); break; } } reactor = pn_reactor(); url = pn_url_parse(address); if (url == NULL) { fprintf(stderr, "Invalid host address %s\n", address); exit(1); } conn = pn_reactor_connection_to_host(reactor, pn_url_get_host(url), pn_url_get_port(url), handler); pn_decref(url); pn_decref(handler); // the container name should be unique for each client pn_connection_set_container(conn, container); // wait up to 5 seconds for activity before returning from // pn_reactor_process() pn_reactor_set_timeout(reactor, 5000); pn_reactor_start(reactor); while (pn_reactor_process(reactor)) { /* Returns 'true' until the connection is shut down. * pn_reactor_process() will return true at least once every 5 seconds * (due to the timeout). If no timeout was configured, * pn_reactor_process() returns as soon as it finishes processing all * pending I/O and events. Once the connection has closed, * pn_reactor_process() will return false. */ } pn_decref(reactor); return 0; } qpid-proton-0.14.0/examples/c/reactor/sender.c0000644000175000017500000002576012770711154020464 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include "pncompat/misc_funcs.inc" #include "proton/reactor.h" #include "proton/message.h" #include "proton/connection.h" #include "proton/session.h" #include "proton/link.h" #include "proton/delivery.h" #include "proton/event.h" #include "proton/handlers.h" #include "proton/transport.h" #include "proton/url.h" static int quiet = 0; // Example application data. This data will be instantiated in the event // handler, and is available during event processing. In this example it // holds configuration and state information. // typedef struct { int count; // # messages to send int anon; // use anonymous link if true const char *target; // name of destination target char *msg_data; // pre-encoded outbound message size_t msg_len; // bytes in msg_data } app_data_t; // helper to pull pointer to app_data_t instance out of the pn_handler_t // #define GET_APP_DATA(handler) ((app_data_t *)pn_handler_mem(handler)) // Called when reactor exits to clean up app_data // static void delete_handler(pn_handler_t *handler) { app_data_t *d = GET_APP_DATA(handler); if (d->msg_data) { free(d->msg_data); d->msg_data = NULL; } } /* Process each event posted by the reactor. */ static void event_handler(pn_handler_t *handler, pn_event_t *event, pn_event_type_t type) { app_data_t *data = GET_APP_DATA(handler); switch (type) { case PN_CONNECTION_INIT: { // Create and open all the endpoints needed to send a message // pn_connection_t *conn; pn_session_t *ssn; pn_link_t *sender; conn = pn_event_connection(event); pn_connection_open(conn); ssn = pn_session(conn); pn_session_open(ssn); sender = pn_sender(ssn, "MySender"); // we do not wait for ack until the last message pn_link_set_snd_settle_mode(sender, PN_SND_MIXED); if (!data->anon) { pn_terminus_set_address(pn_link_target(sender), data->target); } pn_link_open(sender); } break; case PN_LINK_FLOW: { // the remote has given us some credit, now we can send messages // static long tag = 0; // a simple tag generator pn_delivery_t *delivery; pn_link_t *sender = pn_event_link(event); int credit = pn_link_credit(sender); while (credit > 0 && data->count > 0) { --credit; --data->count; ++tag; delivery = pn_delivery(sender, pn_dtag((const char *)&tag, sizeof(tag))); pn_link_send(sender, data->msg_data, data->msg_len); pn_link_advance(sender); if (data->count > 0) { // send pre-settled until the last one, then wait for an ack on // the last sent message. This allows the sender to send // messages as fast as possible and then exit when the consumer // has dealt with the last one. // pn_delivery_settle(delivery); } } } break; case PN_DELIVERY: { // Since the example sends all messages but the last pre-settled // (pre-acked), only the last message's delivery will get updated with // the remote state (acked/nacked). // pn_delivery_t *dlv = pn_event_delivery(event); if (pn_delivery_updated(dlv) && pn_delivery_remote_state(dlv)) { uint64_t rs = pn_delivery_remote_state(dlv); int done = 1; switch (rs) { case PN_RECEIVED: // This is not a terminal state - it is informational, and the // peer is still processing the message. done = 0; break; case PN_ACCEPTED: pn_delivery_settle(dlv); if (!quiet) fprintf(stdout, "Send complete!\n"); break; case PN_REJECTED: case PN_RELEASED: case PN_MODIFIED: pn_delivery_settle(dlv); fprintf(stderr, "Message not accepted - code:%lu\n", (unsigned long)rs); break; default: // ??? no other terminal states defined, so ignore anything else pn_delivery_settle(dlv); fprintf(stderr, "Unknown delivery failure - code=%lu\n", (unsigned long)rs); break; } if (done) { // initiate clean shutdown of the endpoints pn_link_t *link = pn_delivery_link(dlv); pn_session_t *ssn = pn_link_session(link); pn_link_close(link); pn_session_close(ssn); pn_connection_close(pn_session_connection(ssn)); } } } break; case PN_TRANSPORT_ERROR: { // The connection to the peer failed. // pn_transport_t *tport = pn_event_transport(event); pn_condition_t *cond = pn_transport_condition(tport); fprintf(stderr, "Network transport failed!\n"); if (pn_condition_is_set(cond)) { const char *name = pn_condition_get_name(cond); const char *desc = pn_condition_get_description(cond); fprintf(stderr, " Error: %s Description: %s\n", (name) ? name : "", (desc) ? desc : ""); } // pn_reactor_process() will exit with a false return value, stopping // the main loop. } break; default: break; } } static void usage(void) { printf("Usage: send \n"); printf("-a \tThe host address [localhost:5672]\n"); printf("-c \t# of messages to send [1]\n"); printf("-t \tTarget address [examples]\n"); printf("-n \tUse an anonymous link [off]\n"); printf("-i \tContainer name [SendExample]\n"); printf("-q \tQuiet - turn off stdout\n"); printf("message \tA text string to send.\n"); exit(1); } int main(int argc, char** argv) { const char *address = "localhost"; const char *msgtext = "Hello World!"; const char *container = "SendExample"; int c; pn_message_t *message = NULL; pn_data_t *body = NULL; pn_reactor_t *reactor = NULL; pn_url_t *url = NULL; pn_connection_t *conn = NULL; /* Create a handler for the connection's events. event_handler() will be * called for each event and delete_handler will be called when the * connection is released. The handler will allocate an app_data_t * instance which can be accessed when the event_handler is called. */ pn_handler_t *handler = pn_handler_new(event_handler, sizeof(app_data_t), delete_handler); /* set up the application data with defaults */ app_data_t *app_data = GET_APP_DATA(handler); memset(app_data, 0, sizeof(app_data_t)); app_data->count = 1; app_data->target = "examples"; /* Attach the pn_handshaker() handler. This handler deals with endpoint * events from the peer so we don't have to. */ { pn_handler_t *handshaker = pn_handshaker(); pn_handler_add(handler, handshaker); pn_decref(handshaker); } /* command line options */ opterr = 0; while((c = getopt(argc, argv, "i:a:c:t:nhq")) != -1) { switch(c) { case 'h': usage(); break; case 'a': address = optarg; break; case 'c': app_data->count = atoi(optarg); if (app_data->count < 1) usage(); break; case 't': app_data->target = optarg; break; case 'n': app_data->anon = 1; break; case 'i': container = optarg; break; case 'q': quiet = 1; break; default: usage(); break; } } if (optind < argc) msgtext = argv[optind]; // create a single message and pre-encode it so we only have to do that // once. All transmits will use the same pre-encoded message simply for // speed. // message = pn_message(); pn_message_set_address(message, app_data->target); body = pn_message_body(message); pn_data_clear(body); // This message's body contains a single string if (pn_data_fill(body, "S", msgtext)) { fprintf(stderr, "Error building message!\n"); exit(1); } pn_data_rewind(body); { // encode the message, expanding the encode buffer as needed // size_t len = 128; char *buf = (char *)malloc(len); int rc = 0; do { rc = pn_message_encode(message, buf, &len); if (rc == PN_OVERFLOW) { free(buf); len *= 2; buf = (char *)malloc(len); } } while (rc == PN_OVERFLOW); app_data->msg_len = len; app_data->msg_data = buf; } pn_decref(message); // message no longer needed reactor = pn_reactor(); url = pn_url_parse(address); if (url == NULL) { fprintf(stderr, "Invalid host address %s\n", address); exit(1); } conn = pn_reactor_connection_to_host(reactor, pn_url_get_host(url), pn_url_get_port(url), handler); pn_decref(url); pn_decref(handler); // the container name should be unique for each client pn_connection_set_container(conn, container); // wait up to 5 seconds for activity before returning from // pn_reactor_process() pn_reactor_set_timeout(reactor, 5000); pn_reactor_start(reactor); while (pn_reactor_process(reactor)) { /* Returns 'true' until the connection is shut down. * pn_reactor_process() will return true at least once every 5 seconds * (due to the timeout). If no timeout was configured, * pn_reactor_process() returns as soon as it finishes processing all * pending I/O and events. Once the connection has closed, * pn_reactor_process() will return false. */ } pn_decref(reactor); return 0; } qpid-proton-0.14.0/examples/engine/0000755000175000017500000000000012770711154016412 5ustar danieldanielqpid-proton-0.14.0/examples/engine/c/0000755000175000017500000000000012770711154016634 5ustar danieldanielqpid-proton-0.14.0/examples/engine/c/precv.c0000644000175000017500000003571412770711154020131 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 program is half of a pair. Precv and Psend are meant to be simple-as-possible examples of how to use the proton-c engine interface to send and receive messages over a single connection and a single session. In addition to being examples, these programs or their descendants will be used in performance regression testing for both throughput and latency, and long-term soak testing. *################################################################*/ #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include #include #include #define MY_BUF_SIZE 1000 /*--------------------------------------------------------- These high-resolution times are used both for interim timing reports -- i.e. every 'report_frequency' messages -- and for the final timestamp, after all expected messages have been received. ---------------------------------------------------------*/ static double get_time ( ) { struct timeval tv; struct tm * timeinfo; gettimeofday ( & tv, 0 ); timeinfo = localtime ( & tv.tv_sec ); double time_now = 3600 * timeinfo->tm_hour + 60 * timeinfo->tm_min + timeinfo->tm_sec; time_now += ((double)(tv.tv_usec) / 1000000.0); return time_now; } /*---------------------------------------------------- These absolute timestamps are useful in soak tests, where I want to align the program's output with output from top to look at CPU and memory use.. ----------------------------------------------------*/ void print_timestamp_like_a_normal_person ( FILE * fp ) { char const * month_abbrevs[] = { "jan", "feb", "mar", "apr", "may", "jun", "jul", "aug", "sep", "oct", "nov", "dec" }; time_t rawtime; struct tm * timeinfo; time ( & rawtime ); timeinfo = localtime ( &rawtime ); char time_string[100]; sprintf ( time_string, "%d-%s-%02d %02d:%02d:%02d", 1900 + timeinfo->tm_year, month_abbrevs[timeinfo->tm_mon], timeinfo->tm_mday, timeinfo->tm_hour, timeinfo->tm_min, timeinfo->tm_sec ); fprintf ( fp, "timestamp %s\n", time_string ); } int main ( int argc, char ** argv ) { char info[1000]; uint64_t received = 0; char host [1000]; char port [1000]; char output_file_name[1000]; int initial_flow = 400; int flow_increment = 200; int report_frequency = 200000; int64_t messages = 2000000, delivery_count = 0; strcpy ( host, "0.0.0.0" ); strcpy ( port, "5672" ); pn_driver_t * driver; pn_listener_t * listener; pn_connector_t * connector; pn_connection_t * connection; pn_collector_t * collector; pn_transport_t * transport; pn_sasl_t * sasl; pn_session_t * session; pn_event_t * event; pn_link_t * link; pn_delivery_t * delivery; double last_time, this_time, time_diff; char * message_data = (char *) malloc ( MY_BUF_SIZE ); int message_data_capacity = MY_BUF_SIZE; FILE * output_fp; /*----------------------------------------------------------- Read the command lines args and override initialization. -----------------------------------------------------------*/ for ( int i = 1; i < argc; ++ i ) { if ( ! strcmp ( "--host", argv[i] ) ) { strcpy ( host, argv[i+1] ); ++ i; } else if ( ! strcmp ( "--port", argv[i] ) ) { strcpy ( port, argv[i+1] ); ++ i; } else if ( ! strcmp ( "--messages", argv[i] ) ) { sscanf ( argv [ i+1 ], "%" SCNd64 , & messages ); ++ i; } else if ( ! strcmp ( "--output", argv[i] ) ) { if ( ! strcmp ( "stderr", argv[i+1] ) ) { output_fp = stderr; strcpy ( output_file_name, "stderr"); } else if ( ! strcmp ( "stdout", argv[i+1] ) ) { output_fp = stdout; strcpy ( output_file_name, "stdout"); } else { output_fp = fopen ( argv[i+1], "w" ); strcpy ( output_file_name, argv[i+1] ); if ( ! output_fp ) { fprintf ( stderr, "Can't open |%s| for writing.\n", argv[i+1] ); exit ( 1 ); } } ++ i; } else if ( ! strcmp ( "--report_frequency", argv[i] ) ) { report_frequency = atoi ( argv[i+1] ); ++ i; } else if ( ! strcmp ( "--initial_flow", argv[i] ) ) { sscanf ( argv [ i+1 ], "%d", & initial_flow ); ++ i; } else if ( ! strcmp ( "--flow_increment", argv[i] ) ) { sscanf ( argv [ i+1 ], "%d", & flow_increment ); ++ i; } else { fprintf ( output_fp, "unknown arg |%s|\n", argv[i] ); exit ( 1 ); } } /*----------------------------------------------- Show what we ended up with for all the args. -----------------------------------------------*/ fprintf ( output_fp, "host %s\n", host ); fprintf ( output_fp, "port %s\n", port ); fprintf ( output_fp, "messages %" PRId64 "\n", messages ); fprintf ( output_fp, "report_frequency %d\n", report_frequency ); fprintf ( output_fp, "initial_flow %d\n", initial_flow ); fprintf ( output_fp, "flow_increment %d\n", flow_increment ); fprintf ( output_fp, "output %s\n", output_file_name ); /*-------------------------------------------- Create a standard driver and listen for the initial connector. --------------------------------------------*/ driver = pn_driver ( ); if ( ! pn_listener(driver, host, port, 0) ) { fprintf ( output_fp, "precv listener creation failed.\n" ); exit ( 1 ); } fprintf ( output_fp, "\nprecv ready...\n\n" ); while ( 1 ) { pn_driver_wait ( driver, -1 ); if ( listener = pn_driver_listener(driver) ) { if ( connector = pn_listener_accept(listener) ) break; } } /*-------------------------------------------------------- Now make all the other structure around the connector, and tell it that skipping sasl is OK. --------------------------------------------------------*/ connection = pn_connection ( ); collector = pn_collector ( ); pn_connection_collect ( connection, collector ); pn_connector_set_connection ( connector, connection ); transport = pn_connector_transport ( connector ); sasl = pn_sasl ( transport ); pn_sasl_mechanisms ( sasl, "ANONYMOUS" ); pn_sasl_server ( sasl ); pn_sasl_allow_skip ( sasl, true ); pn_sasl_done ( sasl, PN_SASL_OK ); /*---------------------------------------------------------- If report_frequency is not set to zero, we will produce a timing report every report_frequency messages. The timing reported will be the delta from the last_time to the current time. This is useful in soak testing, where you basically never stop, but still need to see how the system is doing every so often. ----------------------------------------------------------*/ last_time = get_time(); /*------------------------------------------------------------ A triply-nested loop. In the outermost one, we just wait for activity to come in from the driver. ------------------------------------------------------------*/ while ( 1 ) { pn_driver_wait ( driver, -1 ); /*--------------------------------------------------------------- In the next loop, we keep going as long as we processed some events. This is because our own processing of events may have caused more to be generated that we need to handle. If we go back to the outermost loop and its pn_driver_wait() without handling these events, we will end up with the sender and receiver programs just staring at each other with blank expressions on their faces. ---------------------------------------------------------------*/ int event_count = 1; while ( event_count > 0 ) { event_count = 0; pn_connector_process ( connector ); /*------------------------------------------------------- After we process the connector, it may have generated a batch of events for us to handle. As we go through this batch of events, our handling may generate other events which we must handle before going back to pn_driver_wait(). --------------------------------------------------------*/ event = pn_collector_peek(collector); while ( event ) { ++ event_count; pn_event_type_t event_type = pn_event_type ( event ); //fprintf ( output_fp, "precv event: %s\n", pn_event_type_name(event_type)); switch ( event_type ) { case PN_CONNECTION_REMOTE_OPEN: break; case PN_SESSION_REMOTE_OPEN: session = pn_event_session(event); if ( pn_session_state(session) & PN_LOCAL_UNINIT ) { // big number because it's in bytes. pn_session_set_incoming_capacity ( session, 1000000 ); pn_session_open ( session ); } break; case PN_LINK_REMOTE_OPEN: /*---------------------------------------------------- When we first open the link, we give it an initial amount of credit in units of messages. We will later increment its credit whenever credit falls below some threshold. ----------------------------------------------------*/ link = pn_event_link(event); if (pn_link_state(link) & PN_LOCAL_UNINIT ) { pn_link_open ( link ); pn_link_flow ( link, initial_flow ); } break; case PN_CONNECTION_BOUND: if ( pn_connection_state(connection) & PN_LOCAL_UNINIT ) { pn_connection_open ( connection ); } break; // And now the event that you've all been waiting for..... case PN_DELIVERY: link = pn_event_link ( event ); delivery = pn_event_delivery ( event ); /*------------------------------------------------ Since I want this program to be a receiver, I am not interested in deliver-related events unless they are incoming, 'readable' events. ------------------------------------------------*/ if ( pn_delivery_readable ( delivery ) ) { // If the delivery is partial I am just going to ignore // it until it becomes complete. if ( ! pn_delivery_partial ( delivery ) ) { ++ delivery_count; /* if ( ! (delivery_count % report_frequency) ) { pn_link_t * delivery_link = pn_delivery_link ( delivery ); int received_bytes = pn_delivery_pending ( delivery ); pn_link_recv ( delivery_link, incoming, 1000 ); fprintf ( output_fp, "received bytes: %d\n", received_bytes ); } */ // don't bother updating. they're pre-settled. // pn_delivery_update ( delivery, PN_ACCEPTED ); pn_delivery_settle ( delivery ); int credit = pn_link_credit ( link ); if ( delivery_count >= messages ) { fprintf ( output_fp, "precv_stop %.3lf\n", get_time() ); goto all_done; } // Make a report frequency of zero shut down interim reporting. if ( report_frequency && (! (delivery_count % report_frequency)) ) { this_time = get_time(); time_diff = this_time - last_time; print_timestamp_like_a_normal_person ( output_fp ); fprintf ( output_fp, "deliveries: %" PRIu64 " time: %.3lf\n", delivery_count, time_diff ); fflush ( output_fp ); last_time = this_time; } /*---------------------------------------------------------- I replenish the credit whevere it falls below this limit because I this psend / precv pair of programs to run as fast as possible. A real application might want to do something fancier here. ----------------------------------------------------------*/ if ( credit <= flow_increment ) { pn_link_flow ( link, flow_increment ); } } } break; case PN_TRANSPORT: // not sure why I would care... break; default: /* fprintf ( output_fp, "precv unhandled event: %s\n", pn_event_type_name(event_type) ); */ break; } pn_collector_pop ( collector ); event = pn_collector_peek(collector); } } } all_done: pn_session_close ( session ); pn_connection_close ( connection ); fclose ( output_fp ); return 0; } qpid-proton-0.14.0/examples/engine/c/psend.c0000644000175000017500000002353712770711154020123 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 program is half of a pair. Precv and Psend are meant to be simple-as-possible examples of how to use the proton-c engine interface to send and receive messages over a single connection and a single session. In addition to being examples, these programs or their descendants will be used in performance regression testing for both throughput and latency, and long-term soak testing. This program, psend, is highly similar to its peer precv. I put all the good comments in precv. *################################################################*/ #include #include #include #include #include #include #include #define __STDC_FORMAT_MACROS #include #include #include #include #include #include #include #include #include #define MY_BUF_SIZE 1000 void print_timestamp ( FILE * fp, char const * label ) { struct timeval tv; struct tm * timeinfo; gettimeofday ( & tv, 0 ); timeinfo = localtime ( & tv.tv_sec ); int seconds_today = 3600 * timeinfo->tm_hour + 60 * timeinfo->tm_min + timeinfo->tm_sec; fprintf ( fp, "time : %d.%.6ld : %s\n", seconds_today, tv.tv_usec, label ); } static double get_time ( ) { struct timeval tv; struct tm * timeinfo; gettimeofday ( & tv, 0 ); timeinfo = localtime ( & tv.tv_sec ); double time_now = 3600 * timeinfo->tm_hour + 60 * timeinfo->tm_min + timeinfo->tm_sec; time_now += ((double)(tv.tv_usec) / 1000000.0); return time_now; } int main ( int argc, char ** argv ) { char addr [ 1000 ]; char host [ 1000 ]; char port [ 1000 ]; char output_file_name[1000]; uint64_t messages = 2000000, delivery_count = 0; int message_length = 100; bool done = false; int sent_count = 0; int n_links = 5; int const max_links = 100; strcpy ( addr, "queue" ); strcpy ( host, "0.0.0.0" ); strcpy ( port, "5672" ); FILE * output_fp; for ( int i = 1; i < argc; ++ i ) { if ( ! strcmp ( "--host", argv[i] ) ) { strcpy ( host, argv[i+1] ); ++ i; } else if ( ! strcmp ( "--port", argv[i] ) ) { strcpy ( port, argv[i+1] ); ++ i; } else if ( ! strcmp ( "--messages", argv[i] ) ) { sscanf ( argv [ i+1 ], "%" SCNd64 , & messages ); ++ i; } else if ( ! strcmp ( "--message_length", argv[i] ) ) { sscanf ( argv [ i+1 ], "%d", & message_length ); ++ i; } else if ( ! strcmp ( "--n_links", argv[i] ) ) { sscanf ( argv [ i+1 ], "%d", & n_links ); ++ i; } if ( ! strcmp ( "--output", argv[i] ) ) { if ( ! strcmp ( "stderr", argv[i+1] ) ) { output_fp = stderr; strcpy ( output_file_name, "stderr"); } else if ( ! strcmp ( "stdout", argv[i+1] ) ) { output_fp = stdout; strcpy ( output_file_name, "stdout"); } else { output_fp = fopen ( argv[i+1], "w" ); strcpy ( output_file_name, argv[i+1] ); if ( ! output_fp ) { fprintf ( stderr, "Can't open |%s| for writing.\n", argv[i+1] ); exit ( 1 ); } } ++ i; } else { fprintf ( output_fp, "unknown arg %s", argv[i] ); } } fprintf ( output_fp, "host %s\n", host ); fprintf ( output_fp, "port %s\n", port ); fprintf ( output_fp, "messages %" PRId64 "\n", messages ); fprintf ( output_fp, "message_length %d\n", message_length ); fprintf ( output_fp, "n_links %d\n", n_links ); fprintf ( output_fp, "output %s\n", output_file_name ); if ( n_links > max_links ) { fprintf ( output_fp, "You can't have more than %d links.\n", max_links ); exit ( 1 ); } pn_driver_t * driver; pn_connector_t * connector; pn_connector_t * driver_connector; pn_connection_t * connection; pn_collector_t * collector; pn_link_t * links [ max_links ]; pn_session_t * session; pn_event_t * event; pn_delivery_t * delivery; char * message = (char *) malloc(message_length); memset ( message, 13, message_length ); /*---------------------------------------------------- Get everything set up. We will have a single connector, a single connection, a single session, and a single link. ----------------------------------------------------*/ driver = pn_driver ( ); connector = pn_connector ( driver, host, port, 0 ); connection = pn_connection(); collector = pn_collector ( ); pn_connection_collect ( connection, collector ); pn_connector_set_connection ( connector, connection ); session = pn_session ( connection ); pn_connection_open ( connection ); pn_session_open ( session ); for ( int i = 0; i < n_links; ++ i ) { char name[100]; sprintf ( name, "tvc_15_%d", i ); links[i] = pn_sender ( session, name ); pn_terminus_set_address ( pn_link_target(links[i]), addr ); pn_link_open ( links[i] ); } /*----------------------------------------------------------- For my speed tests, I do not want to count setup time. Start timing here. The receiver will print out a similar timestamp when he receives the final message. -----------------------------------------------------------*/ fprintf ( output_fp, "psend: sending %llu messages.\n", messages ); // Just before we start sending, print the start timestamp. fprintf ( output_fp, "psend_start %.3lf\n", get_time() ); while ( 1 ) { pn_driver_wait ( driver, -1 ); int event_count = 1; while ( event_count > 0 ) { event_count = 0; pn_connector_process ( connector ); event = pn_collector_peek(collector); while ( event ) { ++ event_count; pn_event_type_t event_type = pn_event_type ( event ); //fprintf ( output_fp, "event: %s\n", pn_event_type_name ( event_type ) ); switch ( event_type ) { case PN_LINK_FLOW: { if ( delivery_count < messages ) { /*--------------------------------------------------- We may have opened multiple links. The event will tell us which one this flow-event happened on. If the flow event gave us some credit, we will greedily send messages until it is all used up. ---------------------------------------------------*/ pn_link_t * link = pn_event_link ( event ); int credit = pn_link_credit ( link ); while ( credit > 0 ) { // Every delivery we create needs a unique tag. char str [ 100 ]; sprintf ( str, "%x", delivery_count ++ ); delivery = pn_delivery ( link, pn_dtag(str, strlen(str)) ); // If you settle the delivery before sending it, // you will spend some time wondering why your // messages don't have any content when they arrive // at the receiver. pn_link_send ( link, message, message_length ); pn_delivery_settle ( delivery ); pn_link_advance ( link ); credit = pn_link_credit ( link ); } if ( delivery_count >= messages ) { fprintf ( output_fp, "I have sent all %d messages.\n" , delivery_count ); /* I'm still kind of hazy on how to shut down the psend / precv system properly .... I can't go to all_done here, or precv will never get all its messages and terminate. So I let precv terminate properly ... which means that this program, psend, dies with an error. Hmm. */ // goto all_done; } } } break; case PN_TRANSPORT: // I don't know what this means here, either. break; case PN_TRANSPORT_TAIL_CLOSED: goto all_done; break; default: /* fprintf ( output_fp, "precv unhandled event: %s\n", pn_event_type_name(event_type) ); */ break; } pn_collector_pop ( collector ); event = pn_collector_peek(collector); } } } all_done: for ( int i = 0; i < n_links; ++ i ) { pn_link_close ( links[i] ); } pn_session_close ( session ); pn_connection_close ( connection ); return 0; } qpid-proton-0.14.0/examples/engine/java/0000755000175000017500000000000012770711154017333 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/LICENSE0000644000175000017500000002607312770711154020350 0ustar danieldanielApache 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.qpid-proton-0.14.0/examples/engine/java/drain0000755000175000017500000000157512770711154020366 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # mvn -q -e exec:java -Dexec.mainClass=org.apache.qpid.proton.examples.Drain -Dexec.args="$*" qpid-proton-0.14.0/examples/engine/java/server0000755000175000017500000000157612770711154020600 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # mvn -q -e exec:java -Dexec.mainClass=org.apache.qpid.proton.examples.Server -Dexec.args="$*" qpid-proton-0.14.0/examples/engine/java/spout0000755000175000017500000000157512770711154020443 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # mvn -q -e exec:java -Dexec.mainClass=org.apache.qpid.proton.examples.Spout -Dexec.args="$*" qpid-proton-0.14.0/examples/engine/java/src/0000755000175000017500000000000012770711154020122 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/0000755000175000017500000000000012770711154021046 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/java/0000755000175000017500000000000012770711154021767 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/java/org/0000755000175000017500000000000012770711154022556 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/0000755000175000017500000000000012770711154023777 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/0000755000175000017500000000000012770711154024734 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/0000755000175000017500000000000012770711154026255 5ustar danieldanielqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/0000755000175000017500000000000012770711154030073 5ustar danieldaniel././@LongLink0000644000000000000000000000015200000000000011601 Lustar rootrootqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/FlowController.javaqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/FlowController0000644000175000017500000000412712770711154032775 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Delivery; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Receiver; /** * FlowController * */ public class FlowController extends BaseHandler { final private int window; public FlowController(int window) { this.window = window; } private void topUp(Receiver rcv) { int delta = window - rcv.getCredit(); rcv.flow(delta); } @Override public void onLinkLocalOpen(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { topUp((Receiver) link); } } @Override public void onLinkRemoteOpen(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { topUp((Receiver) link); } } @Override public void onLinkFlow(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { topUp((Receiver) link); } } @Override public void onDelivery(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { topUp((Receiver) link); } } } ././@LongLink0000644000000000000000000000014600000000000011604 Lustar rootrootqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Handshaker.javaqpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Handshaker.jav0000644000175000017500000000502112770711154032643 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Connection; import org.apache.qpid.proton.engine.EndpointState; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Session; /** * Handshaker * */ public class Handshaker extends BaseHandler { @Override public void onConnectionRemoteOpen(Event evt) { Connection conn = evt.getConnection(); if (conn.getLocalState() == EndpointState.UNINITIALIZED) { conn.open(); } } @Override public void onSessionRemoteOpen(Event evt) { Session ssn = evt.getSession(); if (ssn.getLocalState() == EndpointState.UNINITIALIZED) { ssn.open(); } } @Override public void onLinkRemoteOpen(Event evt) { Link link = evt.getLink(); if (link.getLocalState() == EndpointState.UNINITIALIZED) { link.setSource(link.getRemoteSource()); link.setTarget(link.getRemoteTarget()); link.open(); } } @Override public void onConnectionRemoteClose(Event evt) { Connection conn = evt.getConnection(); if (conn.getLocalState() != EndpointState.CLOSED) { conn.close(); } } @Override public void onSessionRemoteClose(Event evt) { Session ssn = evt.getSession(); if (ssn.getLocalState() != EndpointState.CLOSED) { ssn.close(); } } @Override public void onLinkRemoteClose(Event evt) { Link link = evt.getLink(); if (link.getLocalState() != EndpointState.CLOSED) { link.close(); } } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Message.java0000644000175000017500000000436512770711154032332 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import java.nio.ByteBuffer; import java.util.Arrays; /** * Message * */ public class Message { private final byte[] bytes; /** * These bytes are expected to be AMQP encoded. */ public Message(byte[] bytes) { this.bytes = bytes; } private static final byte[] PREFIX = {(byte)0x00, (byte)0x53, (byte)0x77, (byte)0xb1}; private static byte[] encodeString(String string) { byte[] utf8 = string.getBytes(); byte[] result = new byte[PREFIX.length + 4 + utf8.length]; ByteBuffer bbuf = ByteBuffer.wrap(result); bbuf.put(PREFIX); bbuf.putInt(utf8.length); bbuf.put(utf8); return result; } public Message(String string) { // XXX: special case string encoding for now this(encodeString(string)); } public byte[] getBytes() { return bytes; } public String toString() { StringBuilder bld = new StringBuilder(); bld.append("Message("); for (byte b : bytes) { if (b >= 32 && b < 127) { bld.append((char) b); } else { bld.append("\\x"); String hex = Integer.toHexString(0xFF & b); if (hex.length() < 2) { bld.append("0"); } bld.append(hex); } } bld.append(')'); return bld.toString(); } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Pool.java0000644000175000017500000001210112770711154031642 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import org.apache.qpid.proton.engine.Collector; import org.apache.qpid.proton.engine.Connection; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Session; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Sender; import org.apache.qpid.proton.engine.Receiver; import org.apache.qpid.proton.amqp.messaging.Source; import org.apache.qpid.proton.amqp.messaging.Target; import java.util.HashMap; import java.util.Map; /** * Pool * */ public class Pool { final private Collector collector; final private Map connections; final private LinkConstructor outgoingConstructor = new LinkConstructor () { public Sender create(Session ssn, String remote, String local) { return newOutgoing(ssn, remote, local); } }; final private LinkConstructor incomingConstructor = new LinkConstructor () { public Receiver create(Session ssn, String remote, String local) { return newIncoming(ssn, remote, local); } }; final private LinkResolver outgoingResolver; final private LinkResolver incomingResolver; public Pool(Collector collector, final Router router) { this.collector = collector; connections = new HashMap(); if (router != null) { outgoingResolver = new LinkResolver() { public Sender resolve(String address) { return router.getOutgoing(address).choose(); } }; incomingResolver = new LinkResolver() { public Receiver resolve(String address) { return router.getIncoming(address).choose(); } }; } else { outgoingResolver = new LinkResolver() { public Sender resolve(String address) { return null; } }; incomingResolver = new LinkResolver() { public Receiver resolve(String address) { return null; } }; } } public Pool(Collector collector) { this(collector, null); } private T resolve(String remote, String local, LinkResolver resolver, LinkConstructor constructor) { String host = remote.substring(2).split("/", 2)[0]; T link = resolver.resolve(remote); if (link == null) { Connection conn = connections.get(host); if (conn == null) { conn = Connection.Factory.create(); conn.collect(collector); conn.setHostname(host); conn.open(); connections.put(host, conn); } Session ssn = conn.session(); ssn.open(); link = constructor.create(ssn, remote, local); link.open(); } return link; } public Sender outgoing(String target, String source) { return resolve(target, source, outgoingResolver, outgoingConstructor); } public Receiver incoming(String source, String target) { return resolve(source, target, incomingResolver, incomingConstructor); } public Sender newOutgoing(Session ssn, String remote, String local) { Sender snd = ssn.sender(String.format("%s-%s", local, remote)); Source src = new Source(); src.setAddress(local); snd.setSource(src); Target tgt = new Target(); tgt.setAddress(remote); snd.setTarget(tgt); return snd; } public Receiver newIncoming(Session ssn, String remote, String local) { Receiver rcv = ssn.receiver(String.format("%s-%s", remote, local)); Source src = new Source(); src.setAddress(remote); rcv.setSource(src); Target tgt = new Target(); tgt.setAddress(remote); rcv.setTarget(tgt); return rcv; } public static interface LinkConstructor { T create(Session session, String remote, String local); } public static interface LinkResolver { T resolve(String remote); } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Router.java0000644000175000017500000001214412770711154032220 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import org.apache.qpid.proton.amqp.transport.Source; import org.apache.qpid.proton.amqp.transport.Target; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Receiver; import org.apache.qpid.proton.engine.Sender; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.ThreadLocalRandom; /** * Router * */ public class Router extends BaseHandler { public static class Routes { List routes = new ArrayList(); void add(T route) { routes.add(route); } void remove(T route) { routes.remove(route); } int size() { return routes.size(); } public T choose() { if (routes.isEmpty()) { return null; } ThreadLocalRandom rand = ThreadLocalRandom.current(); int idx = rand.nextInt(0, routes.size()); return routes.get(idx); } } private static final Routes EMPTY_OUT = new Routes(); private static final Routes EMPTY_IN = new Routes(); final private Map> outgoing = new HashMap>(); final private Map> incoming = new HashMap>(); public Router() {} private String getAddress(Source source) { if (source == null) { return null; } else { return source.getAddress(); } } private String getAddress(Target target) { if (target == null) { return null; } else { return target.getAddress(); } } public String getAddress(Sender snd) { String source = getAddress(snd.getSource()); String target = getAddress(snd.getTarget()); return source != null ? source : target; } public String getAddress(Receiver rcv) { return getAddress(rcv.getTarget()); } public Routes getOutgoing(String address) { Routes routes = outgoing.get(address); if (routes == null) { return EMPTY_OUT; } return routes; } public Routes getIncoming(String address) { Routes routes = incoming.get(address); if (routes == null) { return EMPTY_IN; } return routes; } private void add(Sender snd) { String address = getAddress(snd); Routes routes = outgoing.get(address); if (routes == null) { routes = new Routes(); outgoing.put(address, routes); } routes.add(snd); } private void remove(Sender snd) { String address = getAddress(snd); Routes routes = outgoing.get(address); if (routes != null) { routes.remove(snd); if (routes.size() == 0) { outgoing.remove(address); } } } private void add(Receiver rcv) { String address = getAddress(rcv); Routes routes = incoming.get(address); if (routes == null) { routes = new Routes(); incoming.put(address, routes); } routes.add(rcv); } private void remove(Receiver rcv) { String address = getAddress(rcv); Routes routes = incoming.get(address); if (routes != null) { routes.remove(rcv); if (routes.size() == 0) { incoming.remove(address); } } } private void add(Link link) { if (link instanceof Sender) { add((Sender) link); } else { add((Receiver) link); } } private void remove(Link link) { if (link instanceof Sender) { remove((Sender) link); } else { remove((Receiver) link); } } @Override public void onLinkLocalOpen(Event evt) { add(evt.getLink()); } @Override public void onLinkLocalClose(Event evt) { remove(evt.getLink()); } @Override public void onLinkFinal(Event evt) { remove(evt.getLink()); } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Server.java0000644000175000017500000001270412770711154032210 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import org.apache.qpid.proton.amqp.messaging.Accepted; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Collector; import org.apache.qpid.proton.engine.Delivery; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Receiver; import org.apache.qpid.proton.engine.Sender; import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Server * */ public class Server extends BaseHandler { private class MessageStore { Map> messages = new HashMap>(); void put(String address, Message message) { Deque queue = messages.get(address); if (queue == null) { queue = new ArrayDeque(); messages.put(address, queue); } queue.add(message); } Message get(String address) { Deque queue = messages.get(address); if (queue == null) { return null; } Message msg = queue.remove(); if (queue.isEmpty()) { messages.remove(address); } return msg; } } final private MessageStore messages = new MessageStore(); final private Router router; private boolean quiet; private int tag = 0; public Server(Router router, boolean quiet) { this.router = router; this.quiet = quiet; } private byte[] nextTag() { return String.format("%s", tag++).getBytes(); } private int send(String address) { return send(address, null); } private int send(String address, Sender snd) { if (snd == null) { Router.Routes routes = router.getOutgoing(address); snd = routes.choose(); if (snd == null) { return 0; } } int count = 0; while (snd.getCredit() > 0 && snd.getQueued() < 1024) { Message msg = messages.get(address); if (msg == null) { snd.drained(); return count; } Delivery dlv = snd.delivery(nextTag()); byte[] bytes = msg.getBytes(); snd.send(bytes, 0, bytes.length); dlv.settle(); count++; if (!quiet) { System.out.println(String.format("Sent message(%s): %s", address, msg)); } } return count; } @Override public void onLinkFlow(Event evt) { Link link = evt.getLink(); if (link instanceof Sender) { Sender snd = (Sender) link; send(router.getAddress(snd), snd); } } @Override public void onDelivery(Event evt) { Delivery dlv = evt.getDelivery(); Link link = dlv.getLink(); if (link instanceof Sender) { dlv.settle(); } else { Receiver rcv = (Receiver) link; if (!dlv.isPartial()) { byte[] bytes = new byte[dlv.pending()]; rcv.recv(bytes, 0, bytes.length); String address = router.getAddress(rcv); Message message = new Message(bytes); messages.put(address, message); dlv.disposition(Accepted.getInstance()); dlv.settle(); if (!quiet) { System.out.println(String.format("Got message(%s): %s", address, message)); } send(address); } } } public static final void main(String[] argv) throws IOException { List switches = new ArrayList(); List args = new ArrayList(); for (String s : argv) { if (s.startsWith("-")) { switches.add(s); } else { args.add(s); } } boolean quiet = switches.contains("-q"); String host = !args.isEmpty() && !Character.isDigit(args.get(0).charAt(0)) ? args.remove(0) : "localhost"; int port = !args.isEmpty() ? Integer.parseInt(args.remove(0)) : 5672; Collector collector = Collector.Factory.create(); Router router = new Router(); Driver driver = new Driver(collector, new Handshaker(), new FlowController(1024), router, new Server(router, quiet)); driver.listen(host, port); driver.run(); } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Spout.java0000644000175000017500000000730112770711154032051 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import java.util.ArrayList; import java.util.List; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Collector; import org.apache.qpid.proton.engine.Connection; import org.apache.qpid.proton.engine.Delivery; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Sender; public class Spout extends BaseHandler { private int count; private int sent; private int settled; private boolean quiet; public Spout(int count, boolean quiet) { this.count = count; this.quiet = quiet; } @Override public void onLinkFlow(Event evt) { Link link = evt.getLink(); if (link instanceof Sender) { Sender sender = (Sender) link; while ((sent < count) && sender.getCredit() > 0) { Delivery dlv = sender.delivery(String.format("spout-%s", sent).getBytes()); Message msg = new Message(String.format("Hello World! [%s]", sent)); byte[] bytes = msg.getBytes(); sender.send(bytes, 0, bytes.length); sender.advance(); if (!quiet) { System.out.println(String.format("Sent %s to %s: %s", new String(dlv.getTag()), sender.getTarget().getAddress(), msg)); } sent++; } } } @Override public void onDelivery(Event evt) { Delivery dlv = evt.getDelivery(); if (dlv.remotelySettled()) { if (!quiet) { System.out.println(String.format("Settled %s: %s", new String(dlv.getTag()), dlv.getRemoteState())); } dlv.settle(); settled++; } if (settled >= count) { dlv.getLink().getSession().getConnection().close(); } } @Override public void onConnectionRemoteClose(Event evt) { System.out.println("settled: " + settled); } public static void main(String[] argv) throws Exception { List switches = new ArrayList(); List args = new ArrayList(); for (String s : argv) { if (s.startsWith("-")) { switches.add(s); } else { args.add(s); } } boolean quiet = switches.contains("-q"); String address = !args.isEmpty() && args.get(0).startsWith("/") ? args.remove(0) : "//localhost"; int count = !args.isEmpty() ? Integer.parseInt(args.remove(0)) : 1; Collector collector = Collector.Factory.create(); Spout spout = new Spout(count, quiet); Driver driver = new Driver(collector, spout); Pool pool = new Pool(collector); pool.outgoing(address, null); driver.run(); } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Drain.java0000644000175000017500000000757012770711154032004 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import java.util.ArrayList; import java.util.List; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Collector; import org.apache.qpid.proton.engine.Delivery; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Link; import org.apache.qpid.proton.engine.Receiver; public class Drain extends BaseHandler { private int count; private boolean block; private int received; private boolean quiet; public Drain(int count, boolean block, boolean quiet) { this.count = count; this.block = block; this.quiet = quiet; } @Override public void onLinkLocalOpen(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { Receiver receiver = (Receiver) link; if (block) { receiver.flow(count); } else { receiver.drain(count); } } } @Override public void onLinkFlow(Event evt) { Link link = evt.getLink(); if (link instanceof Receiver) { Receiver receiver = (Receiver) link; if (!receiver.draining()) { receiver.getSession().getConnection().close(); } } } @Override public void onDelivery(Event evt) { Delivery dlv = evt.getDelivery(); if (dlv.getLink() instanceof Receiver) { Receiver receiver = (Receiver) dlv.getLink(); if (!dlv.isPartial()) { byte[] bytes = new byte[dlv.pending()]; receiver.recv(bytes, 0, bytes.length); Message msg = new Message(bytes); if (!quiet) { System.out.println(String.format("Got message: %s", msg)); } received++; dlv.settle(); } if ((received >= count) || (!block && !receiver.draining())) { receiver.getSession().getConnection().close(); } } } @Override public void onConnectionRemoteClose(Event evt) { System.out.println(String.format("Got %s messages", received)); } public static void main(String[] argv) throws Exception { List switches = new ArrayList(); List args = new ArrayList(); for (String s : argv) { if (s.startsWith("-")) { switches.add(s); } else { args.add(s); } } boolean quiet = switches.contains("-q"); String address = args.isEmpty() || !args.get(0).startsWith("/") ? "//localhost" : args.remove(0); int count = args.isEmpty() ? 1 : Integer.parseInt(args.remove(0)); boolean block = switches.contains("-b"); Collector collector = Collector.Factory.create(); Drain drain = new Drain(count, block, quiet); Driver driver = new Driver(collector, drain); Pool pool = new Pool(collector); pool.incoming(address, null); driver.run(); } } qpid-proton-0.14.0/examples/engine/java/src/main/java/org/apache/qpid/proton/examples/Driver.java0000644000175000017500000002121512770711154032172 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.examples; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Connection; import org.apache.qpid.proton.engine.Collector; import org.apache.qpid.proton.engine.EndpointState; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Handler; import org.apache.qpid.proton.engine.Sasl; import org.apache.qpid.proton.engine.Transport; import org.apache.qpid.proton.engine.TransportException; import java.io.IOException; import java.net.InetSocketAddress; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.Selector; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.UUID; /** * Driver * */ public class Driver extends BaseHandler { final private Collector collector; final private Handler[] handlers; final private Selector selector; public Driver(Collector collector, Handler ... handlers) throws IOException { this.collector = collector; this.handlers = handlers; this.selector = Selector.open(); } public void listen(String host, int port) throws IOException { new Acceptor(host, port); } public void run() throws IOException { while (true) { processEvents(); // I don't know if there is a better way to do this, but // the only way canceled selection keys are removed from // the key set is via a select operation, so we do this // first to figure out whether we should exit. Without // this we would block indefinitely when there are only // cancelled keys remaining. selector.selectNow(); if (selector.keys().isEmpty()) { selector.close(); return; } selector.selectedKeys().clear(); selector.select(); for (SelectionKey key : selector.selectedKeys()) { Selectable selectable = (Selectable) key.attachment(); selectable.selected(); } } } public void processEvents() { while (true) { Event ev = collector.peek(); if (ev == null) break; ev.dispatch(this); for (Handler h : handlers) { ev.dispatch(h); } collector.pop(); } } @Override public void onTransport(Event evt) { Transport transport = evt.getTransport(); ChannelHandler ch = (ChannelHandler) transport.getContext(); ch.selected(); } @Override public void onConnectionLocalOpen(Event evt) { Connection conn = evt.getConnection(); if (conn.getRemoteState() == EndpointState.UNINITIALIZED) { // Give the connection a [random] container-id conn.setContainer(UUID.randomUUID().toString()); try { new Connector(conn); } catch (IOException e) { throw new RuntimeException(e); } } } private interface Selectable { void selected() throws IOException; } private class Acceptor implements Selectable { final private ServerSocketChannel socket; final private SelectionKey key; Acceptor(String host, int port) throws IOException { socket = ServerSocketChannel.open(); socket.configureBlocking(false); socket.bind(new InetSocketAddress(host, port)); socket.setOption(StandardSocketOptions.SO_REUSEADDR, true); key = socket.register(selector, SelectionKey.OP_ACCEPT, this); } public void selected() throws IOException { SocketChannel sock = socket.accept(); System.out.println("ACCEPTED: " + sock); Connection conn = Connection.Factory.create(); conn.collect(collector); Transport transport = Transport.Factory.create(); Sasl sasl = transport.sasl(); sasl.setMechanisms("ANONYMOUS"); sasl.server(); sasl.done(Sasl.PN_SASL_OK); transport.bind(conn); new ChannelHandler(sock, SelectionKey.OP_READ, transport); } } private class ChannelHandler implements Selectable { final SocketChannel socket; final SelectionKey key; final Transport transport; ChannelHandler(SocketChannel socket, int ops, Transport transport) throws IOException { this.socket = socket; socket.configureBlocking(false); key = socket.register(selector, ops, this); this.transport = transport; transport.setContext(this); } boolean update() { if (socket.isConnected()) { int c = transport.capacity(); int p = transport.pending(); if (key.isValid()) { key.interestOps((c != 0 ? SelectionKey.OP_READ : 0) | (p > 0 ? SelectionKey.OP_WRITE : 0)); } if (c < 0 && p < 0) { return true; } else { return false; } } else { return false; } } public void selected() { if (!key.isValid()) { return; } try { if (key.isConnectable()) { System.out.println("CONNECTED: " + socket); socket.finishConnect(); } if (key.isReadable()) { int c = transport.capacity(); if (c > 0) { ByteBuffer tail = transport.tail(); int n = socket.read(tail); if (n > 0) { try { transport.process(); } catch (TransportException e) { e.printStackTrace(); } } else if (n < 0) { transport.close_tail(); } } } if (key.isWritable()) { int p = transport.pending(); if (p > 0) { ByteBuffer head = transport.head(); int n = socket.write(head); if (n > 0) { transport.pop(n); } else if (n < 0) { transport.close_head(); } } } if (update()) { transport.unbind(); System.out.println("CLOSING: " + socket); socket.close(); } } catch (IOException e) { transport.unbind(); System.out.println(String.format("CLOSING(%s): %s", e, socket)); try { socket.close(); } catch (IOException e2) { throw new RuntimeException(e2); } } } } private static Transport makeTransport(Connection conn) { Transport transport = Transport.Factory.create(); Sasl sasl = transport.sasl(); sasl.setMechanisms("ANONYMOUS"); sasl.client(); transport.bind(conn); return transport; } private class Connector extends ChannelHandler { Connector(Connection conn) throws IOException { super(SocketChannel.open(), SelectionKey.OP_CONNECT, makeTransport(conn)); System.out.println("CONNECTING: " + conn.getHostname()); socket.connect(new InetSocketAddress(conn.getHostname(), 5672)); } } } qpid-proton-0.14.0/examples/engine/java/pom.xml0000644000175000017500000000301712770711154020651 0ustar danieldaniel org.apache.qpid proton-project 0.14.0 ../../../pom.xml 4.0.0 proton-j-engine-demo proton-j-engine-demo org.apache.qpid proton-j ${project.parent.version} qpid-proton-0.14.0/examples/go/0000755000175000017500000000000012770711154015552 5ustar danieldanielqpid-proton-0.14.0/examples/go/CMakeLists.txt0000644000175000017500000000415712770711154020321 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # if(BUILD_GO) set(examples electron/broker electron/receive electron/send proton/broker) file(GLOB_RECURSE example_source FOLLOW_SYMLINKS ${CMAKE_CURRENT_SOURCE_DIR}/*.go) # Build example exes foreach(example ${examples}) string(REPLACE / _ target ${example}) set(target "go_example_${target}") set(output ${CMAKE_CURRENT_BINARY_DIR}/${example}) # Always run go_build, it will do nothing if there is nothing to do. # Otherwise it's too hard to get the dependencies right. add_custom_target(${target} ALL COMMAND ${GO_BUILD} ${GO_EXAMPLE_FLAGS} -o ${output} ${CMAKE_CURRENT_SOURCE_DIR}/${example}.go WORKING_DIRECTORY ${CMAKE_BINARY_DIR} DEPENDS qpid-proton) list(APPEND example_targets ${target}) endforeach() # Build test driver exe set(test_exe ${CMAKE_CURRENT_BINARY_DIR}/example_test) add_custom_target(go_example_test ALL COMMAND ${GO_TEST} -c -o ${test_exe} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.go WORKING_DIRECTORY ${CMAKE_BINARY_DIR}) add_test( NAME go_example_electron_test COMMAND ${GO_ENV} ${test_exe} -dir ${CMAKE_CURRENT_BINARY_DIR}/electron -broker broker) add_test( NAME go_example_proton_test COMMAND ${GO_ENV} ${test_exe} -dir ${CMAKE_CURRENT_BINARY_DIR}/electron -broker ../proton/broker) list(APPEND ADDITIONAL_MAKE_CLEAN_FILES ${examples}) endif() qpid-proton-0.14.0/examples/go/README.md0000644000175000017500000001103412770711154017030 0ustar danieldaniel# Go examples for proton There are 3 Go packages for proton: - qpid.apache.org/electron: Concurrent, procedural API for messaging clients and servers. - qpid.apache.org/proton: Direct access to the event-driven, concurrent-unsafe proton library. - qpid.apache.org/amqp: Convert AMQP messages and data to and from Go data types. `proton` and `electron` are alternative APIs for sending messages. `proton` is a direct wrapping of the concurrent-unsafe, event-driven C proton API. `electron` is a procedural, concurrent-safe interface that may be more convenient and familiar for Go programmers. The examples `proton/broker.go` and `electron/broker.go` give an illustration of how the APIs differ. ## Example programs electron - [receive.go](electron/receive.go) receive from many connections concurrently. - [send.go](electron/send.go) send to many connections concurrently. - [broker.go](electron/broker.go) a simple broker using the electron API proton - [broker.go](proton/broker.go) a simple broker using the proton API ## Using the Go packages If you have the proton C library and headers installed you can get the latest go packages with go get qpid.apache.org/electron If proton is installed in a non-standard place (other than /usr or /usr/local) you can set these environment variables before `go get`, for example: export CGO_LDFLAGS="-L//lib[64]" export CGO_CFLAGS="-I//include" go get qpid.apache.org/electron If you have a proton build you don't need to `go get`, you can set your GOPATH to use the binding from the checkout with: source /config.sh Once you are set up, the go tools will work as normal. You can see documentation in your web browser at `localhost:6060` by running: godoc -http=:6060 ## Running the examples You can run the examples directly from source like this: go run .go This is a little slow (a couple of seconds) as it compiles the program and runs it in one step. You can compile the program first and then run the executable to avoid the delay: go build .go ./ All the examples take a `-h` flag to show usage information, and the comments in the example source have more details. First start the broker (the optional `-debug` flag will print extra information about what the broker is doing) go run broker.go -debug Send messages concurrently to queues "foo" and "bar", 10 messages to each queue: go run send.go -count 10 localhost:/foo localhost:/bar Receive messages concurrently from "foo" and "bar". Note -count 20 for 10 messages each on 2 queues: go run receive.go -count 20 localhost:/foo localhost:/bar The broker and clients use the standard AMQP port (5672) on the local host by default, to use a different address use the `-addr host:port` flag. If you have the full proton repository checked out you can try try using the python broker with Go clients: python ../python/broker.py Or use the Go broker and the python clients: python ../python/simple_send.py python ../python/simple_recv.py ## A tale of two brokers. The `proton` and `electron` packages provide two alternate APIs for AMQP applications. See [the proton Go README](https://github.com/apache/qpid-proton/blob/master/proton-c/bindings/go/src/qpid.apache.org/README.md) for a discussion of why there are two APIs. The examples `proton/broker.go` and `electron/broker.go` both implement the same simple broker-like functionality using each of the two APIs. They both handle multiple connections concurrently and store messages on bounded queues implemented by Go channels. However the `electron/broker` is less than half as long as the `proton/broker` illustrating why it is better suited for most Go applications. `proton/broker` must explicitly handle proton events, which are processed in a single goroutine per connection since proton is not concurrent safe. Each connection uses channels to exchange messages between the event-handling goroutine and the shared queues that are accessible to all connections. Sending messages is particularly tricky since we must monitor the queue for available messages and the sending link for available credit in order to send messages. `electron/broker` takes advantage of the `electron` package, which hides all the event handling and passing of messages between goroutines beind behind straightforward interfaces for sending and receiving messages. The electron broker can implement links as simple goroutines that loop popping messages from a queue and sending them or receiving messages and pushing them to a queue. qpid-proton-0.14.0/examples/go/electron/0000755000175000017500000000000012770711154017365 5ustar danieldanielqpid-proton-0.14.0/examples/go/electron/broker.go0000644000175000017500000001355212770711154021206 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 is a simple AMQP broker implemented using the procedural electron package. // // It maintains a set of named in-memory queues of messages. Clients can send // messages to queues or subscribe to receive messages from them. // package main import ( "../util" "flag" "fmt" "log" "net" "os" "qpid.apache.org/amqp" "qpid.apache.org/electron" ) // Usage and command-line flags func usage() { fmt.Fprintf(os.Stderr, ` Usage: %s A simple broker-like demo. Queues are created automatically for sender or receiver addrsses. `, os.Args[0]) flag.PrintDefaults() } var addr = flag.String("addr", ":amqp", "Listening address") var credit = flag.Int("credit", 100, "Receiver credit window") var qsize = flag.Int("qsize", 1000, "Max queue size") func main() { flag.Usage = usage flag.Parse() b := &broker{ queues: util.MakeQueues(*qsize), container: electron.NewContainer(""), acks: make(chan electron.Outcome), sent: make(chan sentMessage), } if err := b.run(); err != nil { log.Fatal(err) } } // State for the broker type broker struct { queues util.Queues // A collection of queues. container electron.Container // electron.Container manages AMQP connections. sent chan sentMessage // Channel to record sent messages. acks chan electron.Outcome // Channel to receive the Outcome of sent messages. } // Record of a sent message and the queue it came from. // If a message is rejected or not acknowledged due to a failure, we will put it back on the queue. type sentMessage struct { m amqp.Message q util.Queue } // run listens for incoming net.Conn connections and starts an electron.Connection for each one. func (b *broker) run() error { listener, err := net.Listen("tcp", *addr) if err != nil { return err } defer listener.Close() fmt.Printf("Listening on %v\n", listener.Addr()) go b.acknowledgements() // Handles acknowledgements for all connections. // Start a goroutine for each new connections for { conn, err := listener.Accept() if err != nil { util.Debugf("Accept error: %v", err) continue } c, err := b.container.Connection(conn, electron.Server(), electron.AllowIncoming()) if err != nil { util.Debugf("Connection error: %v", err) continue } cc := &connection{b, c} go cc.run() // Handle the connection util.Debugf("Accepted %v", c) } } // State for a broker connectoin type connection struct { broker *broker connection electron.Connection } // accept remotely-opened endpoints (Session, Sender and Receiver) on a connection // and start goroutines to service them. func (c *connection) run() { for in := range c.connection.Incoming() { switch in := in.(type) { case *electron.IncomingSender: if in.Source() == "" { in.Reject(fmt.Errorf("no source")) } else { go c.sender(in.Accept().(electron.Sender)) } case *electron.IncomingReceiver: if in.Target() == "" { in.Reject(fmt.Errorf("no target")) } else { in.SetPrefetch(true) in.SetCapacity(*credit) // Pre-fetch up to credit window. go c.receiver(in.Accept().(electron.Receiver)) } default: in.Accept() // Accept sessions unconditionally } util.Debugf("incoming: %v", in) } util.Debugf("incoming closed: %v", c.connection) } // receiver receives messages and pushes to a queue. func (c *connection) receiver(receiver electron.Receiver) { q := c.broker.queues.Get(receiver.Target()) for { if rm, err := receiver.Receive(); err == nil { util.Debugf("%v: received %v", receiver, util.FormatMessage(rm.Message)) q <- rm.Message rm.Accept() } else { util.Debugf("%v error: %v", receiver, err) break } } } // sender pops messages from a queue and sends them. func (c *connection) sender(sender electron.Sender) { q := c.broker.queues.Get(sender.Source()) for { if sender.Error() != nil { util.Debugf("%v closed: %v", sender, sender.Error()) return } select { case m := <-q: util.Debugf("%v: sent %v", sender, util.FormatMessage(m)) sm := sentMessage{m, q} c.broker.sent <- sm // Record sent message sender.SendAsync(m, c.broker.acks, sm) // Receive outcome on c.broker.acks with Value sm case <-sender.Done(): // break if sender is closed break } } } // acknowledgements keeps track of sent messages and receives outcomes. // // We could have handled outcomes separately per-connection, per-sender or even // per-message. Message outcomes are returned via channels defined by the user // so they can be grouped in any way that suits the application. func (b *broker) acknowledgements() { sentMap := make(map[sentMessage]bool) for { select { case sm, ok := <-b.sent: // A local sender records that it has sent a message. if ok { sentMap[sm] = true } else { return // Closed } case outcome := <-b.acks: // The message outcome is available sm := outcome.Value.(sentMessage) delete(sentMap, sm) if outcome.Status != electron.Accepted { // Error, release or rejection sm.q.PutBack(sm.m) // Put the message back on the queue. util.Debugf("message %v put back, status %v, error %v", util.FormatMessage(sm.m), outcome.Status, outcome.Error) } } } } qpid-proton-0.14.0/examples/go/electron/receive.go0000644000175000017500000000667312770711154021352 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 main import ( "../util" "flag" "fmt" "log" "net" "os" "path" "qpid.apache.org/amqp" "qpid.apache.org/electron" "sync" ) // Usage and command-line flags func usage() { fmt.Fprintf(os.Stderr, `Usage: %s url [url ...] Receive messages from all the listed URLs concurrently and print them. `, os.Args[0]) flag.PrintDefaults() } var count = flag.Uint64("count", 1, "Stop after receiving this many messages.") func main() { flag.Usage = usage flag.Parse() urls := flag.Args() // Non-flag arguments are URLs to receive from if len(urls) == 0 { log.Println("No URL provided") usage() os.Exit(1) } messages := make(chan amqp.Message) // Channel for messages from goroutines to main() defer close(messages) var wait sync.WaitGroup // Used by main() to wait for all goroutines to end. wait.Add(len(urls)) // Wait for one goroutine per URL. _, prog := path.Split(os.Args[0]) container := electron.NewContainer(fmt.Sprintf("%v:%v", prog, os.Getpid())) connections := make(chan electron.Connection, len(urls)) // Connections to close on exit // Start a goroutine to for each URL to receive messages and send them to the messages channel. // main() receives and prints them. for _, urlStr := range urls { util.Debugf("Connecting to %s\n", urlStr) go func(urlStr string) { // Start the goroutine defer wait.Done() // Notify main() when this goroutine is done. url, err := amqp.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults. util.ExitIf(err) // Open a new connection conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port" util.ExitIf(err) c, err := container.Connection(conn) connections <- c // Save connection so we can Close() when main() ends // Create a Receiver using the path of the URL as the source address r, err := c.Receiver(electron.Source(url.Path)) util.ExitIf(err) // Loop receiving messages and sending them to the main() goroutine for { if rm, err := r.Receive(); err != nil { util.Debugf("closed %v: %v", urlStr, err) return } else { rm.Accept() messages <- rm.Message } } }(urlStr) } // All goroutines are started, we are receiving messages. fmt.Printf("Listening on %d connections\n", len(urls)) // print each message until the count is exceeded. for i := uint64(0); i < *count; i++ { m := <-messages util.Debugf("%s\n", util.FormatMessage(m)) } fmt.Printf("Received %d messages\n", *count) // Close all connections, this will interrupt goroutines blocked in Receiver.Receive() for i := 0; i < len(urls); i++ { c := <-connections util.Debugf("close %s", c) c.Close(nil) } wait.Wait() // Wait for all goroutines to finish. } qpid-proton-0.14.0/examples/go/electron/send.go0000644000175000017500000000654412770711154020656 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 main import ( "../util" "flag" "fmt" "log" "net" "os" "path" "qpid.apache.org/amqp" "qpid.apache.org/electron" "sync" ) // Usage and command-line flags func usage() { fmt.Fprintf(os.Stderr, `Usage: %s url [url ...] Send messages to each URL concurrently with body "-" where n is the message number. `, os.Args[0]) flag.PrintDefaults() } var count = flag.Int64("count", 1, "Send this may messages per address.") func main() { flag.Usage = usage flag.Parse() urls := flag.Args() // Non-flag arguments are URLs to receive from if len(urls) == 0 { log.Println("No URL provided") flag.Usage() os.Exit(1) } sentChan := make(chan electron.Outcome) // Channel to receive acknowledgements. var wait sync.WaitGroup wait.Add(len(urls)) // Wait for one goroutine per URL. _, prog := path.Split(os.Args[0]) container := electron.NewContainer(fmt.Sprintf("%v:%v", prog, os.Getpid())) connections := make(chan electron.Connection, len(urls)) // Connctions to close on exit // Start a goroutine for each URL to send messages. for _, urlStr := range urls { util.Debugf("Connecting to %v\n", urlStr) go func(urlStr string) { defer wait.Done() // Notify main() that this goroutine is done. url, err := amqp.ParseURL(urlStr) // Like net/url.Parse() but with AMQP defaults. util.ExitIf(err) // Open a new connection conn, err := net.Dial("tcp", url.Host) // Note net.URL.Host is actually "host:port" util.ExitIf(err) c, err := container.Connection(conn) util.ExitIf(err) connections <- c // Save connection so we can Close() when main() ends // Create a Sender using the path of the URL as the AMQP address s, err := c.Sender(electron.Target(url.Path)) util.ExitIf(err) // Loop sending messages. for i := int64(0); i < *count; i++ { m := amqp.NewMessage() body := fmt.Sprintf("%v-%v", url.Path, i) m.Marshal(body) s.SendAsync(m, sentChan, body) // Outcome will be sent to sentChan } }(urlStr) } // Wait for all the acknowledgements expect := int(*count) * len(urls) util.Debugf("Started senders, expect %v acknowledgements\n", expect) for i := 0; i < expect; i++ { out := <-sentChan // Outcome of async sends. if out.Error != nil { util.Debugf("acknowledgement[%v] %v error: %v\n", i, out.Value, out.Error) } else { util.Debugf("acknowledgement[%v] %v (%v)\n", i, out.Value, out.Status) } } fmt.Printf("Received all %v acknowledgements\n", expect) wait.Wait() // Wait for all goroutines to finish. close(connections) for c := range connections { // Close all connections if c != nil { c.Close(nil) } } } qpid-proton-0.14.0/examples/go/example_test.go0000644000175000017500000001623112770711154020576 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 to verify that example code behaves as expected. // Run in this directory with `go test example_test.go` // package main import ( "bufio" "bytes" "flag" "fmt" "io" "log" "math/rand" "net" "os" "os/exec" "path" "path/filepath" "reflect" "testing" "time" ) func fatalIf(t *testing.T, err error) { if err != nil { t.Fatalf("%s", err) } } // A demo broker process type broker struct { cmd *exec.Cmd addr string runerr chan error err error } // Try to connect to the broker to verify it is ready, give up after a timeout func (b *broker) check() error { dialer := net.Dialer{Deadline: time.Now().Add(time.Second * 10)} for { c, err := dialer.Dial("tcp", b.addr) if err == nil { // Success c.Close() return nil } select { case runerr := <-b.runerr: // Broker exited. return runerr default: } if neterr, ok := err.(net.Error); ok && neterr.Timeout() { // Running but timed out b.stop() return fmt.Errorf("timed out waiting for broker") } time.Sleep(time.Second / 10) } } // Start the demo broker, wait till it is listening on *addr. No-op if already started. func (b *broker) start(t *testing.T) error { if b.cmd == nil { // Not already started b.addr = fmt.Sprintf("127.0.0.1:%d", rand.Intn(10000)+10000) b.cmd = exampleCommand(t, *brokerName, "-addr", b.addr) b.runerr = make(chan error) b.cmd.Stderr, b.cmd.Stdout = os.Stderr, os.Stdout b.err = b.cmd.Start() if b.err == nil { go func() { b.runerr <- b.cmd.Wait() }() } else { b.runerr <- b.err } b.err = b.check() } return b.err } func (b *broker) stop() { if b != nil && b.cmd != nil { b.cmd.Process.Kill() <-b.runerr } } func checkEqual(want interface{}, got interface{}) error { if reflect.DeepEqual(want, got) { return nil } return fmt.Errorf("%#v != %#v", want, got) } // exampleCommand returns an exec.Cmd to run an example. func exampleCommand(t *testing.T, prog string, arg ...string) (cmd *exec.Cmd) { args := []string{} if *debug { args = append(args, "-debug=true") } args = append(args, arg...) prog, err := filepath.Abs(path.Join(*dir, prog)) fatalIf(t, err) if _, err := os.Stat(prog); err == nil { cmd = exec.Command(prog, args...) } else if _, err := os.Stat(prog + ".go"); err == nil { args = append([]string{"run", prog + ".go"}, args...) cmd = exec.Command("go", args...) } else { t.Fatalf("Cannot find binary or source for %s", prog) } cmd.Stderr = os.Stderr return cmd } // Run an example Go program, return the combined output as a string. func runExample(t *testing.T, prog string, arg ...string) (string, error) { cmd := exampleCommand(t, prog, arg...) out, err := cmd.Output() return string(out), err } func prefix(prefix string, err error) error { if err != nil { return fmt.Errorf("%s: %s", prefix, err) } return nil } func runExampleWant(t *testing.T, want string, prog string, args ...string) error { out, err := runExample(t, prog, args...) if err != nil { return fmt.Errorf("%s failed: %s: %s", prog, err, out) } return prefix(prog, checkEqual(want, out)) } func exampleArgs(args ...string) []string { for i := 0; i < *connections; i++ { args = append(args, fmt.Sprintf("%s/%s%d", testBroker.addr, "q", i)) } return args } // Send then receive func TestExampleSendReceive(t *testing.T) { if testing.Short() { t.Skip("Skip demo tests in short mode") } testBroker.start(t) err := runExampleWant(t, fmt.Sprintf("Received all %d acknowledgements\n", expected), "send", exampleArgs("-count", fmt.Sprintf("%d", *count))...) if err != nil { t.Fatal(err) } err = runExampleWant(t, fmt.Sprintf("Listening on %v connections\nReceived %v messages\n", *connections, *count**connections), "receive", exampleArgs("-count", fmt.Sprintf("%d", *count**connections))...) if err != nil { t.Fatal(err) } } var ready error func init() { ready = fmt.Errorf("Ready") } // Run receive in a goroutine. // Send ready on errchan when it is listening. // Send final error when it is done. // Returns the Cmd, caller must Wait() func goReceiveWant(t *testing.T, errchan chan<- error, want string, arg ...string) *exec.Cmd { cmd := exampleCommand(t, "receive", arg...) go func() { pipe, err := cmd.StdoutPipe() if err != nil { errchan <- err return } out := bufio.NewReader(pipe) cmd.Start() line, err := out.ReadString('\n') if err != nil && err != io.EOF { errchan <- err return } listening := "Listening on 3 connections\n" if line != listening { errchan <- checkEqual(listening, line) return } errchan <- ready buf := bytes.Buffer{} io.Copy(&buf, out) // Collect the rest of the output cmd.Wait() errchan <- checkEqual(want, buf.String()) close(errchan) }() return cmd } // Start receiver first, wait till it is running, then send. func TestExampleReceiveSend(t *testing.T) { if testing.Short() { t.Skip("Skip demo tests in short mode") } testBroker.start(t) // Start receiver, wait for "listening" message on stdout recvCmd := exampleCommand(t, "receive", exampleArgs(fmt.Sprintf("-count=%d", expected))...) pipe, err := recvCmd.StdoutPipe() if err != nil { t.Fatal(err) } recvCmd.Start() out := bufio.NewReader(pipe) line, err := out.ReadString('\n') if err := checkEqual("Listening on 3 connections\n", line); err != nil { t.Fatal(err) } if err := runExampleWant(t, fmt.Sprintf("Received all %d acknowledgements\n", expected), "send", exampleArgs("-count", fmt.Sprintf("%d", *count))...); err != nil { t.Fatal(err) } buf := bytes.Buffer{} io.Copy(&buf, out) if err := checkEqual(fmt.Sprintf("Received %d messages\n", expected), buf.String()); err != nil { t.Fatal(err) } } var testBroker *broker var debug = flag.Bool("debug", false, "Debugging output from examples") var brokerName = flag.String("broker", "broker", "Name of broker executable to run") var count = flag.Int("count", 3, "Count of messages to send in tests") var connections = flag.Int("connections", 3, "Number of connections to make in tests") var dir = flag.String("dir", "electron", "Directory containing example sources or binaries") var expected int func TestMain(m *testing.M) { if out, err := exec.Command("go", "install", "qpid.apache.org/...").CombinedOutput(); err != nil { log.Fatalf("go install failed: %s\n%s", err, out) } expected = (*count) * (*connections) rand.Seed(time.Now().UTC().UnixNano()) testBroker = &broker{} // Broker is started on-demand by tests. status := m.Run() testBroker.stop() os.Exit(status) } qpid-proton-0.14.0/examples/go/proton/0000755000175000017500000000000012770711154017073 5ustar danieldanielqpid-proton-0.14.0/examples/go/proton/broker.go0000644000175000017500000002271512770711154020715 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 is a simple AMQP broker implemented using the event-driven proton package. // // It maintains a set of named in-memory queues of messages. Clients can send // messages to queues or subscribe to receive messages from them. // // TODO: show how to handle acknowledgedments from receivers and put rejected or // un-acknowledged messages back on their queues. package main import ( "../util" "flag" "fmt" "log" "net" "os" "qpid.apache.org/amqp" "qpid.apache.org/proton" ) // Usage and command-line flags func usage() { fmt.Fprintf(os.Stderr, ` Usage: %s A simple broker-like demo. Queues are created automatically for sender or receiver addrsses. `, os.Args[0]) flag.PrintDefaults() } var addr = flag.String("addr", ":amqp", "Listening address") var credit = flag.Int("credit", 100, "Receiver credit window") var qsize = flag.Int("qsize", 1000, "Max queue size") func main() { flag.Usage = usage flag.Parse() b := &broker{util.MakeQueues(*qsize)} if err := b.run(); err != nil { log.Fatal(err) } } // State for the broker type broker struct { queues util.Queues } // Listens for connections and starts a proton.Engine for each one. func (b *broker) run() error { listener, err := net.Listen("tcp", *addr) if err != nil { return err } defer listener.Close() fmt.Printf("Listening on %s\n", listener.Addr()) for { conn, err := listener.Accept() if err != nil { util.Debugf("Accept error: %v", err) continue } adapter := proton.NewMessagingAdapter(newHandler(&b.queues)) // We want to accept messages when they are enqueued, not just when they // are received, so we turn off auto-accept and prefetch by the adapter. adapter.Prefetch = 0 adapter.AutoAccept = false engine, err := proton.NewEngine(conn, adapter) if err != nil { util.Debugf("Connection error: %v", err) continue } engine.Server() // Enable server-side protocol negotiation. util.Debugf("Accepted connection %s", engine) go func() { // Start goroutine to run the engine event loop engine.Run() util.Debugf("Closed %s", engine) }() } } // handler handles AMQP events. There is one handler per connection. The // handler does not need to be concurrent-safe as proton.Engine will serialize // all calls to the handler. We use channels to communicate between the handler // goroutine and other goroutines sending and receiving messages. type handler struct { queues *util.Queues receivers map[proton.Link]*receiver senders map[proton.Link]*sender injecter proton.Injecter } func newHandler(queues *util.Queues) *handler { return &handler{ queues: queues, receivers: make(map[proton.Link]*receiver), senders: make(map[proton.Link]*sender), } } // HandleMessagingEvent handles an event, called in the handler goroutine. func (h *handler) HandleMessagingEvent(t proton.MessagingEvent, e proton.Event) { switch t { case proton.MStart: h.injecter = e.Injecter() case proton.MLinkOpening: if e.Link().IsReceiver() { h.startReceiver(e) } else { h.startSender(e) } case proton.MLinkClosed: h.linkClosed(e.Link(), e.Link().RemoteCondition().Error()) case proton.MSendable: if s, ok := h.senders[e.Link()]; ok { s.sendable() // Signal the send goroutine that we have credit. } else { proton.CloseError(e.Link(), amqp.Errorf(amqp.NotFound, "link %s sender not found", e.Link())) } case proton.MMessage: m, err := e.Delivery().Message() // Message() must be called while handling the MMessage event. if err != nil { proton.CloseError(e.Link(), err) break } r, ok := h.receivers[e.Link()] if !ok { proton.CloseError(e.Link(), amqp.Errorf(amqp.NotFound, "link %s receiver not found", e.Link())) break } // This will not block as AMQP credit is set to the buffer capacity. r.buffer <- receivedMessage{e.Delivery(), m} util.Debugf("link %s received %s", e.Link(), util.FormatMessage(m)) case proton.MConnectionClosed, proton.MDisconnected: for l, _ := range h.receivers { h.linkClosed(l, nil) } for l, _ := range h.senders { h.linkClosed(l, nil) } } } // linkClosed is called when a link has been closed by both ends. // It removes the link from the handlers maps and stops its goroutine. func (h *handler) linkClosed(l proton.Link, err error) { if s, ok := h.senders[l]; ok { s.stop() delete(h.senders, l) } else if r, ok := h.receivers[l]; ok { r.stop() delete(h.receivers, l) } } // link has some common data and methods that are used by the sender and receiver types. // // An active link is represented by a sender or receiver value and a goroutine // running its run() method. The run() method communicates with the handler via // channels. type link struct { l proton.Link q util.Queue h *handler } func makeLink(l proton.Link, q util.Queue, h *handler) link { lnk := link{l: l, q: q, h: h} return lnk } // receiver has a channel to buffer messages that have been received by the // handler and are waiting to go on the queue. AMQP credit ensures that the // handler does not overflow the buffer and block. type receiver struct { link buffer chan receivedMessage } // receivedMessage holds a message and a Delivery so that the message can be // acknowledged when it is put on the queue. type receivedMessage struct { delivery proton.Delivery message amqp.Message } // startReceiver creates a receiver and a goroutine for its run() method. func (h *handler) startReceiver(e proton.Event) { q := h.queues.Get(e.Link().RemoteTarget().Address()) r := &receiver{ link: makeLink(e.Link(), q, h), buffer: make(chan receivedMessage, *credit), } h.receivers[r.l] = r r.l.Flow(cap(r.buffer)) // Give credit to fill the buffer to capacity. go r.run() } // run runs in a separate goroutine. It moves messages from the buffer to the // queue for a receiver link, and injects a handler function to acknowledge the // message and send a credit. func (r *receiver) run() { for rm := range r.buffer { r.q <- rm.message d := rm.delivery // We are not in the handler goroutine so we Inject the accept function as a closure. r.h.injecter.Inject(func() { // Check that the receiver is still open, it may have been closed by the remote end. if r == r.h.receivers[r.l] { d.Accept() // Accept the delivery r.l.Flow(1) // Add one credit } }) } } // stop closes the buffer channel and waits for the run() goroutine to stop. func (r *receiver) stop() { close(r.buffer) } // sender has a channel that is used to signal when there is credit to send messages. type sender struct { link credit chan struct{} // Channel to signal availability of credit. } // startSender creates a sender and starts a goroutine for sender.run() func (h *handler) startSender(e proton.Event) { q := h.queues.Get(e.Link().RemoteSource().Address()) s := &sender{ link: makeLink(e.Link(), q, h), credit: make(chan struct{}, 1), // Capacity of 1 for signalling. } h.senders[e.Link()] = s go s.run() } // stop closes the credit channel and waits for the run() goroutine to stop. func (s *sender) stop() { close(s.credit) } // sendable signals that the sender has credit, it does not block. // sender.credit has capacity 1, if it is already full we carry on. func (s *sender) sendable() { select { // Non-blocking case s.credit <- struct{}{}: default: } } // run runs in a separate goroutine. It monitors the queue for messages and injects // a function to send them when there is credit func (s *sender) run() { var q util.Queue // q is nil initially as we have no credit. for { select { case _, ok := <-s.credit: if !ok { // sender closed return } q = s.q // We have credit, enable selecting on the queue. case m, ok := <-q: // q is only enabled when we have credit. if !ok { // queue closed return } q = nil // Assume all credit will be used used, will be signaled otherwise. s.h.injecter.Inject(func() { // Inject handler function to actually send if s.h.senders[s.l] != s { // The sender has been closed by the remote end. q.PutBack(m) // Put the message back on the queue but don't block return } if s.sendOne(m) != nil { return } // Send as many more messages as we can without blocking for s.l.Credit() > 0 { select { // Non blocking receive from q case m, ok := <-s.q: if ok { s.sendOne(m) } default: // Queue is empty but we have credit, signal the run() goroutine. s.sendable() } } }) } } } // sendOne runs in the handler goroutine. It sends a single message. func (s *sender) sendOne(m amqp.Message) error { delivery, err := s.l.Send(m) if err == nil { delivery.Settle() // Pre-settled, unreliable. util.Debugf("link %s sent %s", s.l, util.FormatMessage(m)) } else { s.q.PutBack(m) // Put the message back on the queue, don't block } return err } qpid-proton-0.14.0/examples/go/util/0000755000175000017500000000000012770711154016527 5ustar danieldanielqpid-proton-0.14.0/examples/go/util/queue.go0000644000175000017500000000304712770711154020206 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT 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 util import ( "qpid.apache.org/amqp" "sync" ) // Use a buffered channel as a very simple queue. type Queue chan amqp.Message // Put a message back on the queue, does not block. func (q Queue) PutBack(m amqp.Message) { select { case q <- m: default: // Not an efficient implementation but ensures we don't block the caller. go func() { q <- m }() } } // Concurrent-safe map of queues. type Queues struct { queueSize int m map[string]Queue lock sync.Mutex } func MakeQueues(queueSize int) Queues { return Queues{queueSize: queueSize, m: make(map[string]Queue)} } // Create a queue if not found. func (qs *Queues) Get(name string) Queue { qs.lock.Lock() defer qs.lock.Unlock() q := qs.m[name] if q == nil { q = make(Queue, qs.queueSize) qs.m[name] = q } return q } qpid-proton-0.14.0/examples/go/util/util.go0000644000175000017500000000366512770711154020045 0ustar danieldaniel/* Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to you under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. */ // util contains utility types and functions to simplify parts of the example // code that are not related to the use of proton. package util import ( "flag" "fmt" "log" "os" "path" "qpid.apache.org/amqp" ) // Debug flag "-debug" enables debug output with Debugf var Debug = flag.Bool("debug", false, "Print detailed debug output") // Full flag "-full" enables full message output by FormatMessage var Full = flag.Bool("full", false, "Print full message not just body.") // Debugf logs debug messages if "-debug" flag is set. func Debugf(format string, data ...interface{}) { if *Debug { log.Printf(format, data...) } } // Simple error handling for demo. func ExitIf(err error) { if err != nil { log.Fatal(err) } } // FormatMessage formats a message as a string, just the body by default or // the full message (with properties etc.) if "-full" flag is set. func FormatMessage(m amqp.Message) string { if *Full { return fmt.Sprintf("%#v", m) } else { return fmt.Sprintf("%#v", m.Body()) } } // For example programs, use the program name as the log prefix. func init() { log.SetFlags(0) _, prog := path.Split(os.Args[0]) log.SetPrefix(fmt.Sprintf("%s(%d): ", prog, os.Getpid())) } qpid-proton-0.14.0/examples/java/0000755000175000017500000000000012770711154016066 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/0000755000175000017500000000000012770711154020056 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/README.txt0000644000175000017500000000155612770711154021563 0ustar danieldanielThis directory contains java examples that use the messenger API. Based on the python examples in ../py Send.java - a simple example of using the messenger API to send messages Recv.java - a simple example of using the messenger API to receive messages Note that depending on the address passed into these scripts, you can use them in either a peer to peer or a brokered scenario. For brokered usage: java Recv.class amqp:/// java Send.class -a amqp:/// msg_1 ... msg_n For peer to peer usage: # execute on to receive messages from all local network interfaces java Recv.class amqp://~0.0.0.0 java Send.class -a amqp:// msg_1 ... msg_n Or, use the shell scripts "recv" and "send" to run the java programs: recv [-v] [-n MAXMESSAGES] [-a ADDRESS] ... [-a ADDRESS] send [-a ADDRESS] [-s SUBJECT] MESSAGE ... MESSAGE qpid-proton-0.14.0/examples/java/messenger/recv0000755000175000017500000000245212770711154020746 0ustar danieldaniel#! /bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Usage: recv [-v] [-n MAXMESSAGES] [-a ADDRESS]*" # Subscribes to the given amqp addresses (by default, to amqp://localhost/test), # and prints messages received, upt to MAXMESSAGES. # Prints message headers and body; -v means print all message properties. HERE=$(cd $(dirname $0); pwd) TOP=$(cd $(dirname $0); cd ../../..; pwd) LIBS=$HERE/target/classes:$TOP/proton-j/target/classes JFLAGS="-Djava.util.logging.config.file=$HERE/recv.trace.props -cp $LIBS" java -cp $LIBS org.apache.qpid.proton.example.Recv "$@" qpid-proton-0.14.0/examples/java/messenger/send0000755000175000017500000000230112770711154020731 0ustar danieldaniel#! /bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Usage: send [-a ADDRESS] [-s SUBJECT] MESSAGE ... MESSAGE # sends each arg as a text-message to the given adress (by default, to amqp://localhost/test) HERE=$(cd $(dirname $0); pwd) TOP=$(cd $(dirname $0); cd ../../..; pwd) LIBS=$HERE/target/classes:$TOP/proton-j/target/classes JFLAGS="-Djava.util.logging.config.file=$HERE/send.trace.props -cp $LIBS" java -cp $LIBS org.apache.qpid.proton.example.Send "$@" qpid-proton-0.14.0/examples/java/messenger/src/0000755000175000017500000000000012770711154020645 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/0000755000175000017500000000000012770711154021571 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/0000755000175000017500000000000012770711154022512 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/org/0000755000175000017500000000000012770711154023301 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/org/apache/0000755000175000017500000000000012770711154024522 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/org/apache/qpid/0000755000175000017500000000000012770711154025457 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/org/apache/qpid/proton/0000755000175000017500000000000012770711154027000 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/0000755000175000017500000000000012770711154030433 5ustar danieldanielqpid-proton-0.14.0/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Recv.java0000644000175000017500000001051212770711154032174 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example; import org.apache.qpid.proton.message.Message; import org.apache.qpid.proton.messenger.Messenger; import org.apache.qpid.proton.messenger.impl.MessengerImpl; import org.apache.qpid.proton.amqp.messaging.ApplicationProperties; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.logging.Level; import java.util.logging.Logger; /** * Example/test of the java Messenger/Message API. * Based closely qpid src/proton/examples/messenger/py/recv.py * @author mberkowitz@sf.org * @since 8/4/2013 */ public class Recv { private static Logger tracer = Logger.getLogger("proton.example"); private boolean verbose = false; private int maxct = 0; private List addrs = new ArrayList(); private static void usage() { System.err.println("Usage: recv [-v] [-n MAXCT] [-a ADDRESS]*"); System.exit(2); } private Recv(String args[]) { int i = 0; while (i < args.length) { String arg = args[i++]; if (arg.startsWith("-")) { if ("-v".equals(arg)) { verbose = true; } else if ("-a".equals(arg)) { addrs.add(args[i++]); } else if ("-n".equals(arg)) { maxct = Integer.valueOf(args[i++]); } else { System.err.println("unknown option " + arg); usage(); } } else { usage(); } } if (addrs.size() == 0) { addrs.add("amqp://~0.0.0.0"); } } private static String safe(Object o) { return String.valueOf(o); } private void print(int i, Message msg) { StringBuilder b = new StringBuilder("message: "); b.append(i).append("\n"); b.append("Address: ").append(msg.getAddress()).append("\n"); b.append("Subject: ").append(msg.getSubject()).append("\n"); if (verbose) { b.append("Props: ").append(msg.getProperties()).append("\n"); b.append("App Props: ").append(msg.getApplicationProperties()).append("\n"); b.append("Msg Anno: ").append(msg.getMessageAnnotations()).append("\n"); b.append("Del Anno: ").append(msg.getDeliveryAnnotations()).append("\n"); } else { ApplicationProperties p = msg.getApplicationProperties(); String s = (p == null) ? "null" : safe(p.getValue()); b.append("Headers: ").append(s).append("\n"); } b.append(msg.getBody()).append("\n"); b.append("END").append("\n"); System.out.println(b.toString()); } private void run() { try { Messenger mng = new MessengerImpl(); mng.start(); for (String a : addrs) { mng.subscribe(a); } int ct = 0; boolean done = false; while (!done) { mng.recv(); while (mng.incoming() > 0) { Message msg = mng.get(); ++ct; print(ct, msg); if (maxct > 0 && ct >= maxct) { done = true; break; } } } mng.stop(); } catch (Exception e) { tracer.log(Level.SEVERE, "proton error", e); } } public static void main(String args[]) { Recv o = new Recv(args); o.run(); } } qpid-proton-0.14.0/examples/java/messenger/src/main/java/org/apache/qpid/proton/example/Send.java0000644000175000017500000000604312770711154032172 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example; import org.apache.qpid.proton.amqp.messaging.AmqpValue; import org.apache.qpid.proton.message.Message; import org.apache.qpid.proton.message.impl.MessageImpl; import org.apache.qpid.proton.messenger.Messenger; import org.apache.qpid.proton.messenger.impl.MessengerImpl; import java.io.IOException; import java.util.Arrays; import java.util.logging.Level; import java.util.logging.Logger; /** * Example/test of the java Messenger/Message API. * Based closely qpid src/proton/examples/messenger/py/send.py * @author mberkowitz@sf.org * @since 8/4/2013 */ public class Send { private static Logger tracer = Logger.getLogger("proton.example"); private String address = "amqp://0.0.0.0"; private String subject; private String[] bodies = new String[]{"Hello World!"}; private static void usage() { System.err.println("Usage: send [-a ADDRESS] [-s SUBJECT] MSG+"); System.exit(2); } private Send(String args[]) { int i = 0; while (i < args.length) { String arg = args[i++]; if (arg.startsWith("-")) { if ("-a".equals(arg)) { address = args[i++]; } else if ("-s".equals(arg)) { subject = args[i++]; } else { System.err.println("unknown option " + arg); usage(); } } else { --i; break; } } if(i != args.length) { bodies = Arrays.copyOfRange(args, i, args.length); } } private void run() { try { Messenger mng = new MessengerImpl(); mng.start(); Message msg = new MessageImpl(); msg.setAddress(address); if (subject != null) msg.setSubject(subject); for (String body : bodies) { msg.setBody(new AmqpValue(body)); mng.put(msg); } mng.send(); mng.stop(); } catch (Exception e) { tracer.log(Level.SEVERE, "proton error", e); } } public static void main(String args[]) { Send o = new Send(args); o.run(); } } qpid-proton-0.14.0/examples/java/messenger/pom.xml0000644000175000017500000000313612770711154021376 0ustar danieldaniel org.apache.qpid proton-project 0.14.0 ../../.. 4.0.0 proton-j-messenger-example proton-j-messenger-example org.apache.qpid proton-j ${project.parent.version} http://svn.apache.org/viewvc/qpid/proton/ qpid-proton-0.14.0/examples/java/reactor/0000755000175000017500000000000012770711154017525 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/.gitignore0000644000175000017500000000000512770711154021510 0ustar danieldaniel/bin qpid-proton-0.14.0/examples/java/reactor/README.md0000644000175000017500000000467012770711154021013 0ustar danieldanielThe Reactor API provides a means to dispatch events occurring across one or more connections. It can be used purely as a dispatch tool alongside your own I/O mechanism, however by default it is configured with a handler that provides I/O for you. When programming with the reactor it is important to understand the dispatch model used to process events. Every event is associated with a context object, i.e. the *target* object upon which the event occurred. These objects are contained either directly or indirectly within the Reactor: Delivery --> Link --> Session --> Connection --+ | Task --+--> Reactor | Selectable --+ Each event is dispatched first to a target-specific handler, and second to a global handler. The target-specific handler for an event is located by searching from the event context up through the hierarchy (terminating with the Reactor) and retrieving the most specific handler found. This means that any handler set on the Reactor could receive events targeting any object. For example if no handlers are associated with a Connection or any of its child objects, then the Reactor's handler will receive all the events for that Connection. Putting a handler on any child, e.g. a Connection or Session or Link will prevent any handlers set on the ancestors of that object from seeing any events targeted for that object or its children unless that handler specifically chooses to delegate those events up to the parent, e.g. by overriding onUnhandled and delegating. The global handler (used to dispatch all events after the target-specific handler is invoked) can be accessed and modified using Reactor.set/getGlobalHandler. This can be useful for a number of reasons, e.g. you could log all events by doing this: reactor.getGlobalHandler().add(new LoggerHandler()); Where LoggerHandler does this: public void onUnhandled(Event evt) { System.out.println(evt); } The above trick is particularly useful for debugging. Handlers themselves can have child handlers which will automatically delegate the event to those children *after* dispatching the event to itself. The default global handler is what provides the default I/O behavior of the reactor. To use the reactor as a pure dispatch mechanism you can simply set the global handler to null. qpid-proton-0.14.0/examples/java/reactor/run0000755000175000017500000000162712770711154020265 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # CLASS=$1 shift mvn -q -e exec:java -Dexec.mainClass=org.apache.qpid.proton.example.reactor.${CLASS} -Dexec.args="$*" qpid-proton-0.14.0/examples/java/reactor/src/0000755000175000017500000000000012770711154020314 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/0000755000175000017500000000000012770711154021240 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/0000755000175000017500000000000012770711154022161 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/0000755000175000017500000000000012770711154022750 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/0000755000175000017500000000000012770711154024171 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/0000755000175000017500000000000012770711154025126 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/0000755000175000017500000000000012770711154026447 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/0000755000175000017500000000000012770711154030102 5ustar danieldanielqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/0000755000175000017500000000000012770711154031541 5ustar danieldaniel././@LongLink0000644000000000000000000000014700000000000011605 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Cat.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Cat.ja0000644000175000017500000000706212770711154032571 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.FileInputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe.SourceChannel; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; import org.apache.qpid.proton.reactor.Selectable; public class Cat extends BaseHandler { private class EchoHandler extends BaseHandler { @Override public void onSelectableInit(Event event) { Selectable selectable = event.getSelectable(); // We can configure a selectable with any SelectableChannel we want. selectable.setChannel(channel); // Ask to be notified when the channel is readable selectable.setReading(true); event.getReactor().update(selectable); } @Override public void onSelectableReadable(Event event) { Selectable selectable = event.getSelectable(); // The onSelectableReadable event tells us that there is data // to be read, or the end of stream has been reached. SourceChannel channel = (SourceChannel)selectable.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); try { while(true) { int amount = channel.read(buffer); if (amount < 0) { selectable.terminate(); selectable.getReactor().update(selectable); } if (amount <= 0) break; System.out.write(buffer.array(), 0, buffer.position()); buffer.clear(); } } catch(IOException ioException) { ioException.printStackTrace(); selectable.terminate(); selectable.getReactor().update(selectable); } } } private final SourceChannel channel; private Cat(SourceChannel channel) { this.channel = channel; } @Override public void onReactorInit(Event event) { Reactor reactor = event.getReactor(); Selectable selectable = reactor.selectable(); setHandler(selectable, new EchoHandler()); reactor.update(selectable); } public static void main(String[] args) throws IOException { if (args.length != 1) { System.err.println("Specify a file name as an argument."); System.exit(1); } FileInputStream inFile = new FileInputStream(args[0]); SourceChannel inChannel = EchoInputStreamWrapper.wrap(inFile); Reactor reactor = Proton.reactor(new Cat(inChannel)); reactor.run(); } } ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/CountRandomly.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/CountR0000644000175000017500000000715212770711154032703 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; // Let's try to modify our counter example. In addition to counting to // 10 in quarter second intervals, let's also print out a random number // every half second. This is not a super easy thing to express in a // purely sequential program, but not so difficult using events. public class CountRandomly extends BaseHandler { private long startTime; private CounterHandler counter; class CounterHandler extends BaseHandler { private final int limit; private int count; CounterHandler(int limit) { this.limit = limit; } @Override public void onTimerTask(Event event) { count += 1; System.out.println(count); if (!done()) { event.getReactor().schedule(250, this); } } // Provide a method to check for doneness private boolean done() { return count >= limit; } } @Override public void onReactorInit(Event event) { startTime = System.currentTimeMillis(); System.out.println("Hello, World!"); // Save the counter instance in an attribute so we can refer to // it later. counter = new CounterHandler(10); event.getReactor().schedule(250, counter); // Now schedule another event with a different handler. Note // that the timer tasks go to separate handlers, and they don't // interfere with each other. event.getReactor().schedule(500, this); } @Override public void onTimerTask(Event event) { // keep on shouting until we are done counting System.out.println("Yay, " + Math.round(Math.abs((Math.random() * 110) - 10))); if (!counter.done()) { event.getReactor().schedule(500, this); } } @Override public void onReactorFinal(Event event) { long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("Goodbye, World! (after " + elapsedTime + " long milliseconds)"); } public static void main(String[] args) throws IOException { // In HelloWorld.java we said the reactor exits when there are no more // events to process. While this is true, it's not actually complete. // The reactor exits when there are no more events to process and no // possibility of future events arising. For that reason the reactor // will keep running until there are no more scheduled events and then // exit. Reactor reactor = Proton.reactor(new CountRandomly()); reactor.run(); } } ././@LongLink0000644000000000000000000000015300000000000011602 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Counter.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Counte0000644000175000017500000000572612770711154032733 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; public class Counter extends BaseHandler { private long startTime; class CounterHandler extends BaseHandler { private final int limit; private int count; CounterHandler(int limit) { this.limit = limit; } @Override public void onTimerTask(Event event) { count += 1; System.out.println(count); if (count < limit) { // A recurring task can be accomplished by just scheduling // another event. event.getReactor().schedule(250, this); } } } @Override public void onReactorInit(Event event) { startTime = System.currentTimeMillis(); System.out.println("Hello, World!"); // Note that unlike the previous scheduling example, we pass in // a separate object for the handler. This means that the timer // event we just scheduled will not be seen by the Counter // implementation of BaseHandler as it is being handled by the // CounterHandler instance we create. event.getReactor().schedule(250, new CounterHandler(10)); } @Override public void onReactorFinal(Event event) { long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("Goodbye, World! (after " + elapsedTime + " long milliseconds)"); } public static void main(String[] args) throws IOException { // In HelloWorld.java we said the reactor exits when there are no more // events to process. While this is true, it's not actually complete. // The reactor exits when there are no more events to process and no // possibility of future events arising. For that reason the reactor // will keep running until there are no more scheduled events and then // exit. Reactor reactor = Proton.reactor(new Counter()); reactor.run(); } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Delegates.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Delega0000644000175000017500000000414412770711154032650 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Handler; import org.apache.qpid.proton.reactor.Reactor; // Events know how to dispatch themselves to handlers. By combining // this with on_unhandled, you can provide a kind of inheritance /// between handlers using delegation. public class Delegates extends BaseHandler { private final Handler[] handlers; static class Hello extends BaseHandler { @Override public void onReactorInit(Event e) { System.out.println("Hello, World!"); } } static class Goodbye extends BaseHandler { @Override public void onReactorFinal(Event e) { System.out.println("Goodbye, World!"); } } public Delegates(Handler... handlers) { this.handlers = handlers; } @Override public void onUnhandled(Event event) { for (Handler handler : handlers) { event.dispatch(handler); } } public static void main(String[] args) throws IOException { Reactor reactor = Proton.reactor(new Delegates(new Hello(), new Goodbye())); reactor.run(); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Echo.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Echo.j0000644000175000017500000000721412770711154032576 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Pipe.SourceChannel; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; import org.apache.qpid.proton.reactor.Selectable; public class Echo extends BaseHandler { private class EchoHandler extends BaseHandler { @Override public void onSelectableInit(Event event) { Selectable selectable = event.getSelectable(); // We can configure a selectable with any SelectableChannel we want. selectable.setChannel(channel); // Ask to be notified when the channel is readable selectable.setReading(true); event.getReactor().update(selectable); } @Override public void onSelectableReadable(Event event) { Selectable selectable = event.getSelectable(); // The onSelectableReadable event tells us that there is data // to be read, or the end of stream has been reached. SourceChannel channel = (SourceChannel)selectable.getChannel(); ByteBuffer buffer = ByteBuffer.allocate(1024); try { while(true) { int amount = channel.read(buffer); if (amount < 0) { selectable.terminate(); selectable.getReactor().update(selectable); } if (amount <= 0) break; System.out.write(buffer.array(), 0, buffer.position()); buffer.clear(); } } catch(IOException ioException) { ioException.printStackTrace(); selectable.terminate(); selectable.getReactor().update(selectable); } } } private final SourceChannel channel; private Echo(SourceChannel channel) { this.channel = channel; } @Override public void onReactorInit(Event event) { // Every selectable is a possible source of future events. Our // selectable stays alive until it reads the end of stream // marker. This will keep the whole reactor running until we // type Control-D. System.out.println("Type whatever you want and then use Control-D to exit:"); Reactor reactor = event.getReactor(); Selectable selectable = reactor.selectable(); setHandler(selectable, new EchoHandler()); reactor.update(selectable); } public static void main(String[] args) throws IOException { SourceChannel inChannel = EchoInputStreamWrapper.wrap(System.in); Reactor reactor = Proton.reactor(new Echo(inChannel)); reactor.run(); } } ././@LongLink0000644000000000000000000000017200000000000011603 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/EchoInputStreamWrapper.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/EchoIn0000644000175000017500000000471512770711154032640 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import java.io.InputStream; import java.nio.ByteBuffer; import java.nio.channels.Pipe; import java.nio.channels.Pipe.SinkChannel; import java.nio.channels.Pipe.SourceChannel; import java.util.concurrent.atomic.AtomicInteger; public class EchoInputStreamWrapper extends Thread { private final InputStream in; private final SinkChannel out; private final byte[] bufferBytes = new byte[1024]; private final ByteBuffer buffer = ByteBuffer.wrap(bufferBytes); private final AtomicInteger idCounter = new AtomicInteger(); private EchoInputStreamWrapper(InputStream in, SinkChannel out) { this.in = in; this.out = out; setName(getClass().getName() + "-" + idCounter.incrementAndGet()); setDaemon(true); } @Override public void run() { try { while(true) { int amount = in.read(bufferBytes); if (amount < 0) break; buffer.position(0); buffer.limit(amount); out.write(buffer); } } catch(IOException ioException) { ioException.printStackTrace(); } finally { try { out.close(); } catch(IOException ioException) { ioException.printStackTrace(); } } } public static SourceChannel wrap(InputStream in) throws IOException { Pipe pipe = Pipe.open(); new EchoInputStreamWrapper(in, pipe.sink()).start(); SourceChannel result = pipe.source(); result.configureBlocking(false); return result; } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/GlobalLogger.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Global0000644000175000017500000000521712770711154032671 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; // Not every event goes to the reactor's event handler. If we have a // separate handler for something like a scheduled task, then those // events aren't logged by the logger associated with the reactor's // handler. Sometimes this is useful if you don't want to see them, but // sometimes you want the global picture. public class GlobalLogger extends BaseHandler { static class Logger extends BaseHandler { @Override public void onUnhandled(Event event) { System.out.println("LOG: " + event); } } static class Task extends BaseHandler { @Override public void onTimerTask(Event e) { System.out.println("Mission accomplished!"); } } @Override public void onReactorInit(Event event) { System.out.println("Hello, World!"); event.getReactor().schedule(0, new Task()); } @Override public void onReactorFinal(Event e) { System.out.println("Goodbye, World!"); } public static void main(String[] args) throws IOException { Reactor reactor = Proton.reactor(new GlobalLogger()); // In addition to having a regular handler, the reactor also has a // global handler that sees every event. By adding the Logger to the // global handler instead of the regular handler, we can log every // single event that occurs in the system regardless of whether or not // there are specific handlers associated with the objects that are the // target of those events. reactor.getGlobalHandler().add(new Logger()); reactor.run(); } } ././@LongLink0000644000000000000000000000016000000000000011600 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/GoodbyeWorld.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Goodby0000644000175000017500000000440612770711154032713 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; // So far the reactive hello-world doesn't look too different from a // regular old non-reactive hello-world. The onReactorInit method can // be used roughly as a 'main' method would. A program that only uses // that one event, however, isn't going to be very reactive. By using // other events, we can write a fully reactive program. public class GoodbyeWorld extends BaseHandler { // As before we handle the reactor init event. @Override public void onReactorInit(Event event) { System.out.println("Hello, World!"); } // In addition to an initial event, the reactor also produces an // event when it is about to exit. This may not behave much // differently than just putting the goodbye print statement inside // onReactorInit, but as we grow our program, this piece of it // will always be what happens last, and will always happen // regardless of what other paths the main logic of our program // might take. @Override public void onReactorFinal(Event e) { System.out.println("Goodbye, World!");; } public static void main(String[] args) throws IOException { Reactor reactor = Proton.reactor(new GoodbyeWorld()); reactor.run(); } } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/HelloWorld.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/HelloW0000644000175000017500000000423512770711154032662 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; /* * The proton reactor provides a general purpose event processing * library for writing reactive programs. A reactive program is defined * by a set of event handlers. An event handler is just any class or * object that extends the Handler interface. For convenience, a class * can extend BaseHandler and only handle the events that it cares to * implement methods for. */ public class HelloWorld extends BaseHandler { // The reactor init event is produced by the reactor itself when it // starts. @Override public void onReactorInit(Event event) { System.out.println("Hello, World!"); } public static void main(String[] args) throws IOException { // When you construct a reactor, you can give it a handler that // is used, by default, to receive events generated by the reactor. Reactor reactor = Proton.reactor(new HelloWorld()); // When you call run, the reactor will process events. The reactor init // event is what kicks off everything else. When the reactor has no // more events to process, it exits. reactor.run(); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/README.mdqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/README0000644000175000017500000000145412770711154032425 0ustar danieldanielThe examples in this directory provide a basic introduction to the proton reactor API and are best viewed in the order presented below. The examples contain comments that explain things in a tutorial-style manner. At some point soon this content will be pulled out into a proper tutorial that references the relevant code snippets from these examples. Until then please bear with this clumsy style of presentation. This API is present in Java and Python as well. Most of these examples will transliterate into C in a fairly straightforward way. - HelloWorld.java - GoodbyeWorld.java - Scheduling.java - Counter.java - CountRandomly.java - Unhandled.java - ReactorLogger.java - GlobalLogger.java - Delegates.java - Handlers.java - Echo.java - Cat.java - Send.java - Recv.java ././@LongLink0000644000000000000000000000016100000000000011601 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/ReactorLogger.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Reacto0000644000175000017500000000450612770711154032706 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; public class ReactorLogger extends BaseHandler { public static class Logger extends BaseHandler { @Override public void onUnhandled(Event event) { System.out.println("LOG: " + event); } } @Override public void onReactorInit(Event e) { System.out.println("Hello, World!"); } @Override public void onReactorFinal(Event e) { System.out.println("Goodbye, World!"); } private static boolean loggingEnabled = false; public static void main(String[] args) throws IOException { // You can pass multiple handlers to a reactor when you construct it. // Each of these handlers will see every event the reactor sees. By // combining this with on_unhandled, you can log each event that goes // to the reactor. Reactor reactor = Proton.reactor(new ReactorLogger(), new Logger()); reactor.run(); // Note that if you wanted to add the logger later, you could also // write the above as below. All arguments to the reactor are just // added to the default handler for the reactor. reactor = Proton.reactor(new ReactorLogger()); if (loggingEnabled) reactor.getHandler().add(new Logger()); reactor.run(); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Recv.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Recv.j0000644000175000017500000000533412770711154032620 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.amqp.messaging.AmqpValue; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Delivery; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Receiver; import org.apache.qpid.proton.message.Message; import org.apache.qpid.proton.reactor.FlowController; import org.apache.qpid.proton.reactor.Handshaker; import org.apache.qpid.proton.reactor.Reactor; public class Recv extends BaseHandler { private Recv() { add(new Handshaker()); add(new FlowController()); } @Override public void onReactorInit(Event event) { try { // Create an amqp acceptor. event.getReactor().acceptor("0.0.0.0", 5672); // There is an optional third argument to the Reactor.acceptor // call. Using it, we could supply a handler here that would // become the handler for all accepted connections. If we omit // it, the reactor simply inherits all the connection events. } catch(IOException ioException) { ioException.printStackTrace(); } } @Override public void onDelivery(Event event) { Receiver recv = (Receiver)event.getLink(); Delivery delivery = recv.current(); if (delivery.isReadable() && !delivery.isPartial()) { int size = delivery.pending(); byte[] buffer = new byte[size]; int read = recv.recv(buffer, 0, buffer.length); recv.advance(); Message msg = Proton.message(); msg.decode(buffer, 0, read); System.out.println(((AmqpValue)msg.getBody()).getValue()); } } public static void main(String[] args) throws IOException { Reactor r = Proton.reactor(new Recv()); r.run(); } } ././@LongLink0000644000000000000000000000015600000000000011605 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Scheduling.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Schedu0000644000175000017500000000476112770711154032707 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; import org.apache.qpid.proton.reactor.Task; public class Scheduling extends BaseHandler { private long startTime; @Override public void onReactorInit(Event event) { startTime = System.currentTimeMillis(); System.out.println("Hello, World!"); // We can schedule a task event for some point in the future. // This will cause the reactor to stick around until it has a // chance to process the event. // The first argument is the delay. The second argument is the // handler for the event. We are just using self for now, but // we could pass in another object if we wanted. Task task = event.getReactor().schedule(1000, this); // We can ignore the task if we want to, but we can also use it // to pass stuff to the handler. task.attachments().set("key", String.class, "Yay"); } @Override public void onTimerTask(Event event) { Task task = event.getTask(); System.out.println(task.attachments().get("key", String.class) + " my task is complete!"); } @Override public void onReactorFinal(Event e) { long elapsedTime = System.currentTimeMillis() - startTime; System.out.println("Goodbye, World! (after " + elapsedTime + " long milliseconds)"); } public static void main(String[] args) throws IOException { Reactor reactor = Proton.reactor(new Scheduling()); reactor.run(); } } ././@LongLink0000644000000000000000000000015500000000000011604 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Unhandled.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Unhand0000644000175000017500000000314012770711154032677 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.reactor.Reactor; public class Unhandled extends BaseHandler { // If an event occurs and its handler doesn't have an on_ // method, the reactor will attempt to call the on_unhandled method // if it exists. This can be useful not only for debugging, but for // logging and for delegating/inheritance. @Override public void onUnhandled(Event event) { System.out.println(event); } public static void main(String[] args) throws IOException { Reactor reactor = Proton.reactor(new Unhandled()); reactor.run(); } } ././@LongLink0000644000000000000000000000015000000000000011577 Lustar rootrootqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Send.javaqpid-proton-0.14.0/examples/java/reactor/src/main/java/org/apache/qpid/proton/example/reactor/Send.j0000644000175000017500000001234612770711154032613 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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.proton.example.reactor; import java.io.IOException; import java.nio.BufferOverflowException; import org.apache.qpid.proton.Proton; import org.apache.qpid.proton.amqp.messaging.AmqpValue; import org.apache.qpid.proton.amqp.transport.ErrorCondition; import org.apache.qpid.proton.engine.BaseHandler; import org.apache.qpid.proton.engine.Connection; import org.apache.qpid.proton.engine.Delivery; import org.apache.qpid.proton.engine.Event; import org.apache.qpid.proton.engine.Sender; import org.apache.qpid.proton.engine.Session; import org.apache.qpid.proton.message.Message; import org.apache.qpid.proton.reactor.Handshaker; import org.apache.qpid.proton.reactor.Reactor; // This is a send in terms of low level AMQP events. public class Send extends BaseHandler { private class SendHandler extends BaseHandler { private final Message message; private int nextTag = 0; private SendHandler(Message message) { this.message = message; // Add a child handler that performs some default handshaking // behaviour. add(new Handshaker()); } @Override public void onConnectionInit(Event event) { Connection conn = event.getConnection(); // Every session or link could have their own handler(s) if we // wanted simply by adding the handler to the given session // or link Session ssn = conn.session(); // If a link doesn't have an event handler, the events go to // its parent session. If the session doesn't have a handler // the events go to its parent connection. If the connection // doesn't have a handler, the events go to the reactor. Sender snd = ssn.sender("sender"); conn.open(); ssn.open(); snd.open(); } @Override public void onLinkFlow(Event event) { Sender snd = (Sender)event.getLink(); if (snd.getCredit() > 0) { byte[] msgData = new byte[1024]; int length; while(true) { try { length = message.encode(msgData, 0, msgData.length); break; } catch(BufferOverflowException e) { msgData = new byte[msgData.length * 2]; } } byte[] tag = String.valueOf(nextTag++).getBytes(); Delivery dlv = snd.delivery(tag); snd.send(msgData, 0, length); dlv.settle(); snd.advance(); snd.close(); snd.getSession().close(); snd.getSession().getConnection().close(); } } @Override public void onTransportError(Event event) { ErrorCondition condition = event.getTransport().getCondition(); if (condition != null) { System.err.println("Error: " + condition.getDescription()); } else { System.err.println("Error (no description returned)."); } } } private final String host; private final int port; private final Message message; private Send(String host, int port, String content) { this.host = host; this.port = port; message = Proton.message(); message.setBody(new AmqpValue(content)); } @Override public void onReactorInit(Event event) { // You can use the connection method to create AMQP connections. // This connection's handler is the SendHandler object. All the events // for this connection will go to the SendHandler object instead of // going to the reactor. If you were to omit the SendHandler object, // all the events would go to the reactor. event.getReactor().connectionToHost(host, port, new SendHandler(message)); } public static void main(String[] args) throws IOException { int port = 5672; String host = "localhost"; if (args.length > 0) { String[] parts = args[0].split(":", 2); host = parts[0]; if (parts.length > 1) { port = Integer.parseInt(parts[1]); } } String content = args.length > 1 ? args[1] : "Hello World!"; Reactor r = Proton.reactor(new Send(host, port, content)); r.run(); } } qpid-proton-0.14.0/examples/java/reactor/pom.xml0000644000175000017500000000313412770711154021043 0ustar danieldaniel org.apache.qpid proton-project 0.14.0 ../../.. 4.0.0 proton-j-reactor-examples proton-j-reactor-examples org.apache.qpid proton-j ${project.parent.version} http://svn.apache.org/viewvc/qpid/proton/ qpid-proton-0.14.0/examples/javascript/0000755000175000017500000000000012770711154017313 5ustar danieldanielqpid-proton-0.14.0/examples/javascript/messenger/0000755000175000017500000000000012770711154021303 5ustar danieldanielqpid-proton-0.14.0/examples/javascript/messenger/client.js0000755000175000017500000000674212770711154023133 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Simple client for use with server.js illustrating request/response // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proton = require("qpid-proton-messenger"); var address = "amqp://0.0.0.0"; var subject = "UK.WEATHER"; var replyTo = "~/replies"; var msgtext = "Hello World!"; var tracker = null; var message = new proton.Message(); var messenger = new proton.Messenger(); var pumpData = function() { while (messenger.incoming()) { var t = messenger.get(message); console.log("Reply:"); console.log("Address: " + message.getAddress()); console.log("Subject: " + message.getSubject()); // body is the body as a native JavaScript Object, useful for most real cases. //console.log("Content: " + message.body); // data is the body as a proton.Data Object, used in this case because // format() returns exactly the same representation as recv.c console.log("Content: " + message.data.format()); messenger.accept(t); messenger.stop(); } if (messenger.isStopped()) { message.free(); messenger.free(); } }; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log("Usage: node client.js [-r replyTo] [-s subject] (default " + address + ")"); console.log("Options:"); console.log(" -r The message replyTo (default " + replyTo + ")"); console.log(" -s The message subject (default " + subject + ")"); process.exit(0); } for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg.charAt(0) === '-') { i++; var val = args[i]; if (arg === '-r') { replyTo = val; } else if (arg === '-s') { subject = val; } } else { address = arg; } } } messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.setOutgoingWindow(1024); messenger.recv(); // Receive as many messages as messenger can buffer. messenger.start(); message.setAddress(address); message.setSubject(subject); message.setReplyTo(replyTo); message.body = msgtext; tracker = messenger.put(message); } else { console.error("client.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/drain.js0000755000175000017500000000462012770711154022743 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proton = require("qpid-proton-messenger"); console.log("drain not implemented yet"); process.exit(0); var address = "amqp://~0.0.0.0"; var message = new proton.Message(); var messenger = new proton.Messenger(); var pumpData = function() { while (messenger.incoming()) { var t = messenger.get(message); console.log("Address: " + message.getAddress()); console.log("Subject: " + message.getSubject()); // body is the body as a native JavaScript Object, useful for most real cases. //console.log("Content: " + message.body); // data is the body as a proton.Data Object, used in this case because // format() returns exactly the same representation as recv.c console.log("Content: " + message.data.format()); messenger.accept(t); } }; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log("Usage: recv (default " + address + ")."); process.exit(0); } address = args[0]; } messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.recv(); // Receive as many messages as messenger can buffer. messenger.start(); messenger.subscribe(address); } else { console.error("drain.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/proxy.js0000755000175000017500000001011212770711154023020 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /** * proxy.js is a simple node.js command line application that uses the ws2tcp.js * library to proxy from a WebSocket to a TCP Socket or vice versa. *

* Usage: node proxy.js [options] * Options:"); * -p , --port (default 5673 for ws2tcp * 5672 for tcp2ws) * -t , --tport (default listen port - 1 for ws2tcp * listen port + 1 for tcp2ws) * -h , --thost (default 0.0.0.0) * -m , --method (default ws2tcp) * @Author Fraser Adams * @file */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proxy = require('./ws2tcp.js'); var lport = 5673; var tport = lport - 1; var thost = '0.0.0.0'; var method = 'ws2tcp'; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log("Usage: node proxy.js [options]"); console.log("Options:"); console.log(" -p , --port (default " + lport + " for ws2tcp"); console.log(" " + tport + " for tcp2ws)"); console.log(" -t , --tport (default listen port - 1 for ws2tcp"); console.log(" listen port + 1 for tcp2ws)"); console.log(" -h , --thost (default " + thost + ")"); console.log(" -m , --method (default " + method + ")"); process.exit(0); } var lportSet = false; var tportSet = false; for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg.charAt(0) === '-') { i++; var val = args[i]; if (arg === '-p' || arg === '--port') { lport = val; lportSet = true; } else if (arg === '-t' || arg === '--tport') { tport = val; tportSet = true; } else if (arg === '-h' || arg === '--thost') { thost = val; } else if (arg === '-m' || arg === '--method') { method = val; } } } if (method === 'tcp2ws' && !lportSet) { lport--; } if (!tportSet) { tport = (method === 'ws2tcp') ? lport - 1 : +lport + 1; } } if (method === 'tcp2ws') { console.log("Proxying tcp -> ws"); console.log("Forwarding port " + lport + " to " + thost + ":" + tport); proxy.tcp2ws(lport, thost, tport, 'AMQPWSB10'); } else if (method === 'ws2tcp') { console.log("Proxying ws -> tcp"); console.log("Forwarding port " + lport + " to " + thost + ":" + tport); proxy.ws2tcp(lport, thost, tport); } else { console.error("Method must be either ws2tcp or tcp2ws."); } } else { console.error("proxy.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/qpid-config.js0000755000175000017500000017264212770711154024060 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /** * Port of qpid-config to JavaScript for Node.js, mainly intended as a demo to * illustrate using QMF2 in JavaScript using the proton.Messenger JS binding. * It illustrates a few things including how to use Messenger completely * asynchronously including using an async request/response pattern with * correlation IDs. It also proves interoperability of AMQP Map, List etc. * between C++ and JavaScript as QMF2 is pretty much all about Lists of Maps. *

* The actual QMF2 code is pretty simple as we're just doing a basic getObjects * it's made all the simpler because we can use JavaScript object literals as * the JavaScript binding serialises and deserialises directly between JavaScript * Objects and Lists and the AMQP type system so something that can be quite * involved in languages like C++ and Java becomes quite simple in JavaScript, * though the asynchronous nature of JavaScript provides its own opportunities * for complication best illustrated by the need for the correlator object. */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var qmf = {}; // Create qmf namespace object. qmf.Console = function() { // qmf.Console Constructor. var proton = require("qpid-proton-messenger"); var message = new proton.Message(); var messenger = new proton.Messenger(); var brokerAddress = ''; var replyTo = ''; /** * The correlator object is a mechanism used to correlate requests with * their aynchronous responses. It might possible be better to make use * of Promises to implement part of this behaviour but a mechanism would * still be needed to correlate a request with its response callback in * order to wrap things up in a Promise, so much of the behaviour of this * object would still be required. In addition it seemed to make sense to * make this QMF2 implementation fairly free of dependencies and using * Promises would require external libraries. Instead the correlator * implements "Promise-like" semantics, you might say a broken Promise :-) *

* in particular the request method behaves a *bit* like Promise.all() * though it is mostly fake and takes an array of functions that call * the add() method which is really the method used to associate response * objects by correlationID. The then method is used to register a * listener that will be called when all the requests that have been * registered have received responses. * TODO error/timeout handling. */ var correlator = { _resolve: null, _objects: {}, add: function(id) { this._objects[id] = {complete: false, list: null}; }, request: function() { this._resolve = function() {console.log("Warning: No resolver has been set")}; return this; }, then: function(resolver) { this._resolve = resolver ? resolver : this._resolve; }, resolve: function() { var opcode = message.properties['qmf.opcode']; var correlationID = message.getCorrelationID(); var resp = this._objects[correlationID]; if (opcode === '_query_response') { if (resp.list) { Array.prototype.push.apply(resp.list, message.body); // This is faster than concat. } else { resp.list = message.body; } var partial = message.properties['partial']; if (!partial) { resp.complete = true; } this._objects[correlationID] = resp; this._checkComplete(); } else if (opcode === '_method_response' || opcode === '_exception') { resp.list = message.body; resp.complete = true; this._objects[correlationID] = resp; this._checkComplete(); } else { console.error("Bad Message response, qmf.opcode = " + opcode); } }, _checkComplete: function() { var response = {}; for (var id in this._objects) { var object = this._objects[id]; if (object.complete) { response[id] = object.list; } else { return; } } this._objects = {}; // Clear state ready for next call. this._resolve(response.method ? response.method : response); } }; // End of correlator object definition. var pumpData = function() { while (messenger.incoming()) { // The second parameter forces Binary payloads to be decoded as // strings this is useful because the broker QMF Agent encodes // strings as AMQP binary unfortunately. var t = messenger.get(message, true); correlator.resolve(); messenger.accept(t); } if (messenger.isStopped()) { message.free(); messenger.free(); } }; this.getObjects = function(packageName, className) { message.setAddress(brokerAddress); message.setSubject('broker'); message.setReplyTo(replyTo); message.setCorrelationID(className); message.properties = { "routing-key": "broker", // Added for Java Broker "x-amqp-0-10.app-id": "qmf2", "method": "request", "qmf.opcode": "_query_request", }; message.body = { "_what": "OBJECT", "_schema_id": { "_package_name": packageName, "_class_name": className } }; correlator.add(className); messenger.put(message); }; this.invokeMethod = function(object, method, arguments) { var correlationID = 'method'; message.setAddress(brokerAddress); message.setSubject('broker'); message.setReplyTo(replyTo); message.setCorrelationID(correlationID); message.properties = { "routing-key": "broker", // Added for Java Broker "x-amqp-0-10.app-id": "qmf2", "method": "request", "qmf.opcode": "_method_request", }; message.body = { "_object_id": object._object_id, "_method_name" : method, "_arguments" : arguments }; correlator.add(correlationID); messenger.put(message); }; this.addConnection = function(addr, callback) { brokerAddress = addr + '/qmf.default.direct'; var replyAddress = addr + '/#'; messenger.on('subscription', function(subscription) { var subscriptionAddress = subscription.getAddress(); var splitAddress = subscriptionAddress.split('/'); replyTo = splitAddress[splitAddress.length - 1]; callback(); }); messenger.subscribe(replyAddress); } this.destroy = function() { messenger.stop(); } this.request = function() {return correlator.request();} messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.setOutgoingWindow(1024); messenger.recv(); // Receive as many messages as messenger can buffer. messenger.start(); }; // End of qmf.Console /************************* qpid-config business logic ************************/ var brokerAgent = new qmf.Console(); var _usage = 'Usage: qpid-config [OPTIONS]\n' + ' qpid-config [OPTIONS] exchanges [filter-string]\n' + ' qpid-config [OPTIONS] queues [filter-string]\n' + ' qpid-config [OPTIONS] add exchange [AddExchangeOptions]\n' + ' qpid-config [OPTIONS] del exchange \n' + ' qpid-config [OPTIONS] add queue [AddQueueOptions]\n' + ' qpid-config [OPTIONS] del queue [DelQueueOptions]\n' + ' qpid-config [OPTIONS] bind [binding-key]\n' + ' [-f -|filename]\n' + ' [all|any] k1=v1 [, k2=v2...]\n' + ' qpid-config [OPTIONS] unbind [binding-key]\n' + ' qpid-config [OPTIONS] reload-acl\n' + ' qpid-config [OPTIONS] add [--argument =]\n' + ' qpid-config [OPTIONS] del \n' + ' qpid-config [OPTIONS] list [--show-property ]\n'; var usage = function() { console.log(_usage); process.exit(-1); }; var _description = 'Examples:\n' + '\n' + '$ qpid-config add queue q\n' + '$ qpid-config add exchange direct d -a localhost:5672\n' + '$ qpid-config exchanges -b 10.1.1.7:10000\n' + '$ qpid-config queues -b guest/guest@broker-host:10000\n' + '\n' + 'Add Exchange values:\n' + '\n' + ' direct Direct exchange for point-to-point communication\n' + ' fanout Fanout exchange for broadcast communication\n' + ' topic Topic exchange that routes messages using binding keys with wildcards\n' + ' headers Headers exchange that matches header fields against the binding keys\n' + ' xml XML Exchange - allows content filtering using an XQuery\n' + '\n' + '\n' + 'Queue Limit Actions:\n' + '\n' + ' none (default) - Use broker\'s default policy\n' + ' reject - Reject enqueued messages\n' + ' ring - Replace oldest unacquired message with new\n' + '\n' + 'Replication levels:\n' + '\n' + ' none - no replication\n' + ' configuration - replicate queue and exchange existence and bindings, but not messages.\n' + ' all - replicate configuration and messages\n'; var _options = 'Options:\n' + ' -h, --help show this help message and exit\n' + '\n' + ' General Options:\n' + ' -t , --timeout=\n' + ' Maximum time to wait for broker connection (in\n' + ' seconds)\n' + ' -r, --recursive Show bindings in queue or exchange list\n' + ' -b

, --broker=
\n' + ' Address of qpidd broker with syntax:\n' + ' [username/password@] hostname | ip-address [:]\n' + ' -a
, --broker-addr=
\n' + /* TODO Connection options ' --sasl-mechanism=\n' + ' SASL mechanism for authentication (e.g. EXTERNAL,\n' + ' ANONYMOUS, PLAIN, CRAM-MD5, DIGEST-MD5, GSSAPI). SASL\n' + ' automatically picks the most secure available\n' + ' mechanism - use this option to override.\n' + ' --ssl-certificate=\n' + ' Client SSL certificate (PEM Format)\n' + ' --ssl-key= Client SSL private key (PEM Format)\n' + ' --ha-admin Allow connection to a HA backup broker.\n' + */ '\n' + ' Options for Listing Exchanges and Queues:\n' + ' --ignore-default Ignore the default exchange in exchange or queue list\n' + '\n' + ' Options for Adding Exchanges and Queues:\n' + ' --alternate-exchange=\n' + ' Name of the alternate-exchange for the new queue or\n' + ' exchange. Exchanges route messages to the alternate\n' + ' exchange if they are unable to route them elsewhere.\n' + ' Queues route messages to the alternate exchange if\n' + ' they are rejected by a subscriber or orphaned by queue\n' + ' deletion.\n' + ' --durable The new queue or exchange is durable.\n' + ' --replicate=\n' + ' Enable automatic replication in a HA cluster. \n' + ' is \'none\', \'configuration\' or \'all\').\n' + '\n' + ' Options for Adding Queues:\n' + ' --file-count= Number of files in queue\'s persistence journal\n' + ' --file-size= File size in pages (64KiB/page)\n' + ' --max-queue-size=\n' + ' Maximum in-memory queue size as bytes\n' + ' --max-queue-count=\n' + ' Maximum in-memory queue size as a number of messages\n' + ' --limit-policy=\n' + ' Action to take when queue limit is reached\n' + ' --lvq-key= Last Value Queue key\n' + ' --generate-queue-events=\n' + ' If set to 1, every enqueue will generate an event that\n' + ' can be processed by registered listeners (e.g. for\n' + ' replication). If set to 2, events will be generated\n' + ' for enqueues and dequeues.\n' + ' --flow-stop-size=\n' + ' Turn on sender flow control when the number of queued\n' + ' bytes exceeds this value.\n' + ' --flow-resume-size=\n' + ' Turn off sender flow control when the number of queued\n' + ' bytes drops below this value.\n' + ' --flow-stop-count=\n' + ' Turn on sender flow control when the number of queued\n' + ' messages exceeds this value.\n' + ' --flow-resume-count=\n' + ' Turn off sender flow control when the number of queued\n' + ' messages drops below this value.\n' + ' --group-header=\n' + ' Enable message groups. Specify name of header that\n' + ' holds group identifier.\n' + ' --shared-groups Allow message group consumption across multiple\n' + ' consumers.\n' + ' --argument=\n' + ' Specify a key-value pair to add to queue arguments\n' + ' --start-replica=\n' + ' Start replication from the same-named queue at\n' + ' \n' + '\n' + ' Options for Adding Exchanges:\n' + ' --sequence Exchange will insert a \'qpid.msg_sequence\' field in\n' + ' the message header\n' + ' --ive Exchange will behave as an \'initial-value-exchange\',\n' + ' keeping a reference to the last message forwarded and\n' + ' enqueuing that message to newly bound queues.\n' + '\n' + ' Options for Deleting Queues:\n' + ' --force Force delete of queue even if it\'s currently used or\n' + ' it\'s not empty\n' + ' --force-if-not-empty\n' + ' Force delete of queue even if it\'s not empty\n' + ' --force-if-used Force delete of queue even if it\'s currently used\n' + '\n' + ' Options for Declaring Bindings:\n' + ' -f , --file=\n' + ' For XML Exchange bindings - specifies the name of a\n' + ' file containing an XQuery.\n' + '\n' + ' Formatting options for \'list\' action:\n' + ' --show-property=\n' + ' Specify a property of an object to be included in\n' + ' output\n'; var REPLICATE_LEVELS = {"none" : true, "configuration": true, "all": true}; var DEFAULT_PROPERTIES = {"exchange": {"name": true, "type": true, "durable": true}, "queue": {"name": true, "durable": true, "autoDelete": true}}; var getValue = function(r) { var value = null; if (r.length === 2) { value = r[1]; if (!isNaN(value)) { value = parseInt(value); } } return value; }; var config = { _recursive : false, _host : 'guest:guest@localhost:5673', // Note 5673 not 5672 as we use WebSocket transport. _connTimeout : 10, _ignoreDefault : false, _altern_ex : null, _durable : false, _replicate : null, _if_empty : true, _if_unused : true, _fileCount : null, _fileSize : null, _maxQueueSize : null, _maxQueueCount : null, _limitPolicy : null, _msgSequence : false, _lvq_key : null, _ive : null, _eventGeneration: null, _file : null, _flowStopCount : null, _flowResumeCount: null, _flowStopSize : null, _flowResumeSize : null, _msgGroupHeader : null, _sharedMsgGroup : false, _extra_arguments: [], _start_replica : null, _returnCode : 0, _list_properties: null, getOptions: function() { var options = {}; for (var a = 0; a < this._extra_arguments.length; a++) { var r = this._extra_arguments[a].split('='); options[r[0]] = getValue(r); } return options; } }; var FILECOUNT = 'qpid.file_count'; var FILESIZE = 'qpid.file_size'; var MAX_QUEUE_SIZE = 'qpid.max_size'; var MAX_QUEUE_COUNT = 'qpid.max_count'; var POLICY_TYPE = 'qpid.policy_type'; var LVQ_KEY = 'qpid.last_value_queue_key'; var MSG_SEQUENCE = 'qpid.msg_sequence'; var IVE = 'qpid.ive'; var QUEUE_EVENT_GENERATION = 'qpid.queue_event_generation'; var FLOW_STOP_COUNT = 'qpid.flow_stop_count'; var FLOW_RESUME_COUNT = 'qpid.flow_resume_count'; var FLOW_STOP_SIZE = 'qpid.flow_stop_size'; var FLOW_RESUME_SIZE = 'qpid.flow_resume_size'; var MSG_GROUP_HDR_KEY = 'qpid.group_header_key'; var SHARED_MSG_GROUP = 'qpid.shared_msg_group'; var REPLICATE = 'qpid.replicate'; /** * There are various arguments to declare that have specific program * options in this utility. However there is now a generic mechanism for * passing arguments as well. The SPECIAL_ARGS list contains the * arguments for which there are specific program options defined * i.e. the arguments for which there is special processing on add and * list */ var SPECIAL_ARGS={}; SPECIAL_ARGS[FILECOUNT] = true; SPECIAL_ARGS[FILESIZE] = true; SPECIAL_ARGS[MAX_QUEUE_SIZE] = true; SPECIAL_ARGS[MAX_QUEUE_COUNT] = true; SPECIAL_ARGS[POLICY_TYPE] = true; SPECIAL_ARGS[LVQ_KEY] = true; SPECIAL_ARGS[MSG_SEQUENCE] = true; SPECIAL_ARGS[IVE] = true; SPECIAL_ARGS[QUEUE_EVENT_GENERATION] = true; SPECIAL_ARGS[FLOW_STOP_COUNT] = true; SPECIAL_ARGS[FLOW_RESUME_COUNT] = true; SPECIAL_ARGS[FLOW_STOP_SIZE] = true; SPECIAL_ARGS[FLOW_RESUME_SIZE] = true; SPECIAL_ARGS[MSG_GROUP_HDR_KEY] = true; SPECIAL_ARGS[SHARED_MSG_GROUP] = true; SPECIAL_ARGS[REPLICATE] = true; // Returns a String representation of an ObjectID. var oid = function(id) { return id._agent_epoch + ':' + id._object_name }; // Check if the supplied name contains the supplied filter String. var filterMatch = function(name, filter) { if (filter === '') { return true; } if (name.indexOf(filter) === -1) { return false; } return true; }; // Take the supplied List of QMF2 Objects and return a Map keyed by ObjectID. var idMap = function(list) { var map = {}; for (var i = 0; i < list.length; i++) { var item = list[i]; map[oid(item._object_id)] = item; } return map; }; // Pretty-print the supplied Object. var renderObject = function(obj, list) { if (!obj) { return ''; } var string = ''; var addComma = false; for (var prop in obj) { if (addComma) { string += ', '; } if (obj.hasOwnProperty(prop)) { if (list) { if (SPECIAL_ARGS[prop]) continue; string += " --argument " + prop + "=" + obj[prop]; } else { string += "'" + prop + "'" + ": '" + obj[prop] + "'"; addComma = true; } } } if (addComma) { return '{' + string + '}'; } else { if (list) { return string; } else { return ''; } } }; /** * The following methods illustrate the QMF2 class query mechanism which returns * the list of QMF Objects for the specified class that are currently present * on the Broker. The Schema /cpp/src/qpid/broker/management-schema.xml * describes the properties and statistics of each Management Object. *

* One slightly subtle part of QMF is that certain Objects are associated via * references, for example Binding contains queueRef and exchangeRef, which lets * Objects link to each other using their _object_id property. *

* The implementation of these methods attempts to follow the same general flow * as the equivalent method in the "canonical" python based qpid-config version * but has the added complication that JavaScript is entirely asynchronous. * The approach that has been taken is to use the correlator object that lets a * callback function be registered via the "then" method and actually calls the * callback when all of the requests specified in the request method have * returned their results (which get passed as the callback parameter). */ var overview = function() { brokerAgent.request( // Send the QMF query requests for the specified classes. brokerAgent.getObjects('org.apache.qpid.broker', 'queue'), brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') ).then(function(objects) { var exchanges = objects.exchange; var queues = objects.queue; console.log("Total Exchanges: " + exchanges.length); var etype = {}; for (var i = 0; i < exchanges.length; i++) { var exchange = exchanges[i]._values; if (!etype[exchange.type]) { etype[exchange.type] = 1; } else { etype[exchange.type]++; } } for (var typ in etype) { var pad = Array(16 - typ.length).join(' '); console.log(pad + typ + ": " + etype[typ]); } console.log("\n Total Queues: " + queues.length); var durable = 0; for (var i = 0; i < queues.length; i++) { var queue = queues[i]._values; if (queue.durable) { durable++; } } console.log(" durable: " + durable); console.log(" non-durable: " + (queues.length - durable)); brokerAgent.destroy(); }); }; var exchangeList = function(filter) { brokerAgent.request( // Send the QMF query requests for the specified classes. brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') ).then(function(objects) { var exchanges = objects.exchange; var exMap = idMap(exchanges); var caption1 = "Type "; var caption2 = "Exchange Name"; var maxNameLen = caption2.length; var found = false; for (var i = 0; i < exchanges.length; i++) { var exchange = exchanges[i]._values; if (filterMatch(exchange.name, filter)) { if (exchange.name.length > maxNameLen) { maxNameLen = exchange.name.length; } found = true; } } if (!found) { config._returnCode = 1; return; } var pad = Array(maxNameLen + 1 - caption2.length).join(' '); console.log(caption1 + caption2 + pad + " Attributes"); console.log(Array(maxNameLen + caption1.length + 13).join('=')); for (var i = 0; i < exchanges.length; i++) { var exchange = exchanges[i]._values; if (config._ignoreDefault && !exchange.name) continue; if (filterMatch(exchange.name, filter)) { var pad1 = Array(11 - exchange.type.length).join(' '); var pad2 = Array(maxNameLen + 2 - exchange.name.length).join(' '); var string = exchange.type + pad1 + exchange.name + pad2; var args = exchange.arguments ? exchange.arguments : {}; if (exchange.durable) { string += ' --durable'; } if (args[REPLICATE]) { string += ' --replicate=' + args[REPLICATE]; } if (args[MSG_SEQUENCE]) { string += ' --sequence'; } if (args[IVE]) { string += ' --ive'; } if (exchange.altExchange) { string += ' --alternate-exchange=' + exMap[oid(exchange.altExchange)]._values.name; } console.log(string); } } brokerAgent.destroy(); }); }; var exchangeListRecurse = function(filter) { brokerAgent.request( // Send the QMF query requests for the specified classes. brokerAgent.getObjects('org.apache.qpid.broker', 'queue'), brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'), brokerAgent.getObjects('org.apache.qpid.broker', 'binding') ).then(function(objects) { var exchanges = objects.exchange; var bindings = objects.binding; var queues = idMap(objects.queue); for (var i = 0; i < exchanges.length; i++) { var exchange = exchanges[i]; var exchangeId = oid(exchange._object_id); exchange = exchange._values; if (config._ignoreDefault && !exchange.name) continue; if (filterMatch(exchange.name, filter)) { console.log("Exchange '" + exchange.name + "' (" + exchange.type + ")"); for (var j = 0; j < bindings.length; j++) { var bind = bindings[j]._values; var exchangeRef = oid(bind.exchangeRef); if (exchangeRef === exchangeId) { var queue = queues[oid(bind.queueRef)]; var queueName = queue ? queue._values.name : ""; console.log(" bind [" + bind.bindingKey + "] => " + queueName + " " + renderObject(bind.arguments)); } } } } brokerAgent.destroy(); }); }; var queueList = function(filter) { brokerAgent.request( // Send the QMF query requests for the specified classes. brokerAgent.getObjects('org.apache.qpid.broker', 'queue'), brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') ).then(function(objects) { var queues = objects.queue; var exMap = idMap(objects.exchange); var caption = "Queue Name"; var maxNameLen = caption.length; var found = false; for (var i = 0; i < queues.length; i++) { var queue = queues[i]._values; if (filterMatch(queue.name, filter)) { if (queue.name.length > maxNameLen) { maxNameLen = queue.name.length; } found = true; } } if (!found) { config._returnCode = 1; return; } var pad = Array(maxNameLen + 1 - caption.length).join(' '); console.log(caption + pad + " Attributes"); console.log(Array(maxNameLen + caption.length + 3).join('=')); for (var i = 0; i < queues.length; i++) { var queue = queues[i]._values; if (filterMatch(queue.name, filter)) { var pad2 = Array(maxNameLen + 2 - queue.name.length).join(' '); var string = queue.name + pad2; var args = queue.arguments ? queue.arguments : {}; if (queue.durable) { string += ' --durable'; } if (args[REPLICATE]) { string += ' --replicate=' + args[REPLICATE]; } if (queue.autoDelete) { string += ' auto-del'; } if (queue.exclusive) { string += ' excl'; } if (args[FILESIZE]) { string += ' --file-size=' + args[FILESIZE]; } if (args[FILECOUNT]) { string += ' --file-count=' + args[FILECOUNT]; } if (args[MAX_QUEUE_SIZE]) { string += ' --max-queue-size=' + args[MAX_QUEUE_SIZE]; } if (args[MAX_QUEUE_COUNT]) { string += ' --max-queue-count=' + args[MAX_QUEUE_COUNT]; } if (args[POLICY_TYPE]) { string += ' --limit-policy=' + args[POLICY_TYPE].replace("_", "-"); } if (args[LVQ_KEY]) { string += ' --lvq-key=' + args[LVQ_KEY]; } if (args[QUEUE_EVENT_GENERATION]) { string += ' --generate-queue-events=' + args[QUEUE_EVENT_GENERATION]; } if (queue.altExchange) { string += ' --alternate-exchange=' + exMap[oid(queue.altExchange)]._values.name; } if (args[FLOW_STOP_SIZE]) { string += ' --flow-stop-size=' + args[FLOW_STOP_SIZE]; } if (args[FLOW_RESUME_SIZE]) { string += ' --flow-resume-size=' + args[FLOW_RESUME_SIZE]; } if (args[FLOW_STOP_COUNT]) { string += ' --flow-stop-count=' + args[FLOW_STOP_COUNT]; } if (args[FLOW_RESUME_COUNT]) { string += ' --flow-resume-count=' + args[FLOW_RESUME_COUNT]; } if (args[MSG_GROUP_HDR_KEY]) { string += ' --group-header=' + args[MSG_GROUP_HDR_KEY]; } if (args[SHARED_MSG_GROUP] === 1) { string += ' --shared-groups'; } string += ' ' + renderObject(args, true); console.log(string); } } brokerAgent.destroy(); }); }; var queueListRecurse = function(filter) { brokerAgent.request( // Send the QMF query requests for the specified classes. brokerAgent.getObjects('org.apache.qpid.broker', 'queue'), brokerAgent.getObjects('org.apache.qpid.broker', 'exchange'), brokerAgent.getObjects('org.apache.qpid.broker', 'binding') ).then(function(objects) { var queues = objects.queue; var bindings = objects.binding; var exchanges = idMap(objects.exchange); for (var i = 0; i < queues.length; i++) { var queue = queues[i]; var queueId = oid(queue._object_id); queue = queue._values; if (filterMatch(queue.name, filter)) { console.log("Queue '" + queue.name + "'"); for (var j = 0; j < bindings.length; j++) { var bind = bindings[j]._values; var queueRef = oid(bind.queueRef); if (queueRef === queueId) { var exchange = exchanges[oid(bind.exchangeRef)]; var exchangeName = ""; if (exchange) { exchangeName = exchange._values.name; if (exchangeName === '') { if (config._ignoreDefault) continue; exchangeName = "''"; } } console.log(" bind [" + bind.bindingKey + "] => " + exchangeName + " " + renderObject(bind.arguments)); } } } } brokerAgent.destroy(); }); }; /** * The following methods implement adding and deleting various Broker Management * Objects via QMF. Although /cpp/src/qpid/broker/management-schema.xml * describes the basic method schema, for example: * * * * * * * * * * * * * * What the schema doesn't do however is to explain what the properties/options * Map values actually mean, unfortunately these aren't documented anywhere so * the only option is to look in the code, the best place to look is in: * /cpp/src/qpid/broker/Broker.cpp, the method Broker::ManagementMethod is * the best place to start, then Broker::createObject and Broker::deleteObject * even then it's pretty hard to figure out all that is possible. */ var handleMethodResponse = function(response, dontStop) { if (response._arguments) { //console.log(response._arguments); } if (response._values) { console.error("Exception from Agent: " + renderObject(response._values)); } // Mostly we want to stop the Messenger Event loop and exit when a QMF method // returns, but sometimes we don't, the dontStop flag prevents this behaviour. if (!dontStop) { brokerAgent.destroy(); } } var addExchange = function(args) { if (args.length < 2) { usage(); } var etype = args[0]; var ename = args[1]; var declArgs = {}; declArgs['exchange-type'] = etype; for (var a = 0; a < config._extra_arguments.length; a++) { var r = config._extra_arguments[a].split('='); declArgs[r[0]] = getValue(r); } if (config._msgSequence) { declArgs[MSG_SEQUENCE] = 1; } if (config._ive) { declArgs[IVE] = 1; } if (config._altern_ex) { declArgs['alternate-exchange'] = config._altern_ex; } if (config._durable) { declArgs['durable'] = 1; } if (config._replicate) { declArgs[REPLICATE] = config._replicate; } brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( brokerAgent.invokeMethod(broker, 'create', { "type": "exchange", "name": ename, "properties": declArgs, "strict": true}) ).then(handleMethodResponse); }); }; var delExchange = function(args) { if (args.length < 1) { usage(); } var ename = args[0]; brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( brokerAgent.invokeMethod(broker, 'delete', { "type": "exchange", "name": ename}) ).then(handleMethodResponse); }); }; var addQueue = function(args) { if (args.length < 1) { usage(); } var qname = args[0]; var declArgs = {}; for (var a = 0; a < config._extra_arguments.length; a++) { var r = config._extra_arguments[a].split('='); declArgs[r[0]] = getValue(r); } if (config._durable) { // allow the default fileCount and fileSize specified // in qpid config file to take prededence if (config._fileCount) { declArgs[FILECOUNT] = config._fileCount; } if (config._fileSize) { declArgs[FILESIZE] = config._fileSize; } } if (config._maxQueueSize != null) { declArgs[MAX_QUEUE_SIZE] = config._maxQueueSize; } if (config._maxQueueCount != null) { declArgs[MAX_QUEUE_COUNT] = config._maxQueueCount; } if (config._limitPolicy) { if (config._limitPolicy === 'none') { } else if (config._limitPolicy === 'reject') { declArgs[POLICY_TYPE] = 'reject'; } else if (config._limitPolicy === 'ring') { declArgs[POLICY_TYPE] = 'ring'; } } if (config._lvq_key) { declArgs[LVQ_KEY] = config._lvq_key; } if (config._eventGeneration) { declArgs[QUEUE_EVENT_GENERATION] = config._eventGeneration; } if (config._flowStopSize != null) { declArgs[FLOW_STOP_SIZE] = config._flowStopSize; } if (config._flowResumeSize != null) { declArgs[FLOW_RESUME_SIZE] = config._flowResumeSize; } if (config._flowStopCount != null) { declArgs[FLOW_STOP_COUNT] = config._flowStopCount; } if (config._flowResumeCount != null) { declArgs[FLOW_RESUME_COUNT] = config._flowResumeCount; } if (config._msgGroupHeader) { declArgs[MSG_GROUP_HDR_KEY] = config._msgGroupHeader; } if (config._sharedMsgGroup) { declArgs[SHARED_MSG_GROUP] = 1; } if (config._altern_ex) { declArgs['alternate-exchange'] = config._altern_ex; } if (config._durable) { declArgs['durable'] = 1; } if (config._replicate) { declArgs[REPLICATE] = config._replicate; } // This block is a little complex and untidy, the real issue is that the // correlator object isn't as good as a real Promise and doesn't support // chaining of "then" calls, so where we have complex dependencies we still // get somewhat into "callback hell". TODO improve the correlator. brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( brokerAgent.invokeMethod(broker, 'create', { "type": "queue", "name": qname, "properties": declArgs, "strict": true}) ).then(function(response) { if (config._start_replica) { handleMethodResponse(response, true); // The second parameter prevents exiting. // TODO test this stuff! brokerAgent.request( brokerAgent.getObjects('org.apache.qpid.ha', 'habroker') // Not sure if this is correct ).then(function(objects) { if (objects.habroker.length > 0) { var habroker = objects.habroker[0]; brokerAgent.request( brokerAgent.invokeMethod(habroker, 'replicate', { "broker": config._start_replica, "queue": qname}) ).then(handleMethodResponse); } else { brokerAgent.destroy(); } }); } else { handleMethodResponse(response); } }); }); }; var delQueue = function(args) { if (args.length < 1) { usage(); } var qname = args[0]; brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( brokerAgent.invokeMethod(broker, 'delete', { "type": "queue", "name": qname, "options": {"if_empty": config._if_empty, "if_unused": config._if_unused}}) ).then(handleMethodResponse); }); }; var snarf_header_args = function(args) { if (args.length < 2) { console.log("Invalid args to bind headers: need 'any'/'all' plus conditions"); return false; } var op = args[0]; if (op === 'all' || op === 'any') { kv = {}; var bindings = Array.prototype.slice.apply(args, [1]); for (var i = 0; i < bindings.length; i++) { var binding = bindings[i]; binding = binding.split(",")[0]; binding = binding.split("="); kv[binding[0]] = binding[1]; } kv['x-match'] = op; return kv; } else { console.log("Invalid condition arg to bind headers, need 'any' or 'all', not '" + op + "'"); return false; } }; var bind = function(args) { if (args.length < 2) { usage(); } var ename = args[0]; var qname = args[1]; var key = ''; if (args.length > 2) { key = args[2]; } brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker'), brokerAgent.getObjects('org.apache.qpid.broker', 'exchange') // Get exchanges to look up exchange type. ).then(function(objects) { var exchanges = objects.exchange; var etype = ''; for (var i = 0; i < exchanges.length; i++) { var exchange = exchanges[i]._values; if (exchange.name === ename) { etype = exchange.type; break; } } // type of the xchg determines the processing of the rest of // argv. if it's an xml xchg, we want to find a file // containing an x-query, and pass that. if it's a headers // exchange, we need to pass either "any" or all, followed by a // map containing key/value pairs. if neither of those, extra // args are ignored. var declArgs = {}; if (etype === 'xml') { } else if (etype === 'headers') { declArgs = snarf_header_args(Array.prototype.slice.apply(args, [3])); } //console.log(declArgs); if (typeof declArgs !== 'object') { process.exit(1); } var broker = objects.broker[0]; brokerAgent.request( brokerAgent.invokeMethod(broker, 'create', { "type": "binding", "name": ename + '/' + qname + '/' + key, "properties": declArgs, "strict": true}) ).then(handleMethodResponse); }); /* ok = True _args = {} if not res: pass elif res.type == "xml": # this checks/imports the -f arg [ok, xquery] = snarf_xquery_args() _args = { "xquery" : xquery } else: if res.type == "headers": [ok, op, kv] = snarf_header_args(args[3:]) _args = kv _args["x-match"] = op if not ok: sys.exit(1) self.broker.bind(ename, qname, key, _args) */ }; var unbind = function(args) { if (args.length < 2) { usage(); } var ename = args[0]; var qname = args[1]; var key = ''; if (args.length > 2) { key = args[2]; } brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( brokerAgent.invokeMethod(broker, 'delete', { "type": "binding", "name": ename + '/' + qname + '/' + key}) ).then(handleMethodResponse); }); }; /** * The following methods are "generic" create and delete methods to for arbitrary * Management Objects e.g. Incoming, Outgoing, Domain, Topic, QueuePolicy, * TopicPolicy etc. use --argument k1=v1 --argument k2=v2 --argument k3=v3 to * pass arbitrary arguments as key/value pairs to the Object being created/deleted, * for example to add a topic object that uses the fanout exchange: * ./qpid-config.js add topic fanout --argument exchange=amq.fanout \ * --argument qpid.max_size=1000000 --argument qpid.policy_type=ring */ var createObject = function(type, name, args) { brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( // Create an object of the specified type. brokerAgent.invokeMethod(broker, 'create', { "type": type, "name": name, "properties": args, "strict": true}) ).then(handleMethodResponse); }); }; var deleteObject = function(type, name, args) { brokerAgent.request( // We invoke the CRUD methods on the broker object. brokerAgent.getObjects('org.apache.qpid.broker', 'broker') ).then(function(objects) { var broker = objects.broker[0]; brokerAgent.request( // Create an object of the specified type and name. brokerAgent.invokeMethod(broker, 'delete', { "type": type, "name": name, "options": args}) ).then(handleMethodResponse); }); }; /** * This is a "generic" mechanism for listing arbitrary Management Objects. */ var listObjects = function(type) { brokerAgent.request( brokerAgent.getObjects('org.apache.qpid.broker', type) ).then(function(objects) { // The correlator passes an object containing responses for all of the // supplied requests so we index it by the supplied type to get our response. objects = objects[type]; // Collect available attributes, stringify the values and compute the max // length of the value of each attribute so that we can later create a table. var attributes = {}; var lengths = {}; for (var i = 0; i < objects.length; i++) { var object = objects[i]; object = object._values; for (var prop in object) { if (typeof object[prop] === 'object') { // Stringify Object properties. // Check if property is an ObjectID (reference property), // if so replace with the "name" part of the OID. if (object[prop]['_object_name']) { var parts = object[prop]['_object_name'].split(':'); object[prop] = parts[parts.length - 1]; } else { // Stringify general Object properties. object[prop] = renderObject(object[prop]); } } else { object[prop] = object[prop].toString(); // Stringify other property types. } if (!lengths[prop] || object[prop].length > lengths[prop]) { // Compute lengths. lengths[prop] = object[prop].length > prop.length ? object[prop].length : prop.length; } if (!config._list_properties || config._list_properties[prop]) { // Do we want this property? attributes[prop] = true; } } } if (!config._list_properties && DEFAULT_PROPERTIES[type]) { attributes = DEFAULT_PROPERTIES[type]; } // Using the information we've previously prepared now render a table // showing the required property values. var desired = []; var header = ''; // Table header showing the property names. if (attributes['name']) { desired.push('name'); delete attributes['name']; header += 'name' + Array(lengths['name'] + 2 - 4).join(' '); } for (var prop in attributes) { desired.push(prop); header += prop + Array(lengths[prop] + 2 - prop.length).join(' '); } console.log("Objects of type '" + type + "'"); console.log(header); console.log(Array(header.length).join('=')); for (var i = 0; i < objects.length; i++) { var object = objects[i]; object = object._values; var string = ''; for (var j = 0; j < desired.length; j++) { var key = desired[j]; string += object[key] + Array(lengths[key] + 2 - object[key].length).join(' '); } console.log(string); } brokerAgent.destroy(); }); }; var reloadAcl = function() { brokerAgent.request( brokerAgent.getObjects('org.apache.qpid.acl', 'acl') ).then(function(objects) { if (objects.acl.length > 0) { var acl = objects.acl[0]; brokerAgent.request( // Create an object of the specified type. brokerAgent.invokeMethod(acl, 'reloadACLFile', {}) ).then(handleMethodResponse); } else { console.log("Failed: No ACL Loaded in Broker"); brokerAgent.destroy(); } }); }; /********************* process command line options **********************/ var params = []; var extra_arguments = []; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log(_usage); console.log(_description); console.log(_options); process.exit(0); } for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg === '-r' || arg === '--recursive') { config._recursive = true; } else if (arg === '--ignore-default') { config._ignoreDefault = true; } else if (arg === '--durable') { config._durable = true; } else if (arg === '--shared-groups') { config._sharedMsgGroup = true; } else if (arg === '--sequence') { config._sequence = true; } else if (arg === '--ive') { config._ive = true; } else if (arg === '--force') { config._if_empty = false; config._if_unused = false; } else if (arg === '--force-if-not-empty') { config._if_empty = false; } else if (arg === '--force-if-used') { config._if_unused = false; } else if (arg === '--sequence') { config._msgSequence = true; } else if (arg.charAt(0) === '-') { i++; var val = args[i]; if (arg === '-t' || arg === '--timeout') { config._connTimeout = parseInt(val); if (config._connTimeout === 0) { config._connTimeout = null; } } else if (arg === '-b' || arg === '--broker' || arg === '-a' || arg === '--broker-addr') { if (val != null) { config._host = val; } } else if (arg === '--alternate-exchange') { config._altern_ex = val; } else if (arg === '--replicate') { if (!REPLICATE_LEVELS[val]) { console.error("Invalid replication level " + val + ", should be one of 'none', 'configuration' or 'all'"); } config._replicate = val; } else if (arg === '--file-count') { config._fileCount = parseInt(val); } else if (arg === '--file-size') { config._fileSize = parseInt(val); } else if (arg === '--max-queue-size') { config._maxQueueSize = parseInt(val); } else if (arg === '--max-queue-count') { config._maxQueueCount = parseInt(val); } else if (arg === '--limit-policy') { config._limitPolicy = val; } else if (arg === '--lvq-key') { config._lvq_key = val; } else if (arg === '--generate-queue-events') { config._eventGeneration = parseInt(val); } else if (arg === '--flow-stop-size') { config._flowStopSize = parseInt(val); } else if (arg === '--flow-resume-size') { config._flowResumeSize = parseInt(val); } else if (arg === '--flow-stop-count') { config._flowStopCount = parseInt(val); } else if (arg === '--flow-resume-count') { config._flowResumeCount = parseInt(val); } else if (arg === '--group-header') { config._msgGroupHeader = val; } else if (arg === '--argument') { extra_arguments.push(val); } else if (arg === '--start-replica') { config._start_replica = val; } else if (arg === '--f' || arg === '--file') { // TODO Won't work in node.js config._file = val; } else if (arg === '--show-property') { if (config._list_properties === null) { config._list_properties = {}; } config._list_properties[val] = true; } } else { params.push(arg); } } } config._extra_arguments = extra_arguments; // The command only *actually* gets called when the QMF connection has actually // been established so we wrap up the function we want to get called in a lambda. var command = function() {overview();}; if (params.length > 0) { var cmd = params[0]; var modifier = ''; if (params.length > 1) { modifier = params[1]; } if (cmd === 'exchanges') { if (config._recursive) { command = function() {exchangeListRecurse(modifier);}; } else { command = function() {exchangeList(modifier);}; } } else if (cmd === 'queues') { if (config._recursive) { command = function() {queueListRecurse(modifier);}; } else { command = function() {queueList(modifier);}; } } else if (cmd === 'add') { if (modifier === 'exchange') { command = function() {addExchange(Array.prototype.slice.apply(params, [2]));}; } else if (modifier === 'queue') { command = function() {addQueue(Array.prototype.slice.apply(params, [2]));}; } else if (params.length > 2) { command = function() {createObject(modifier, params[2], config.getOptions());}; } else { usage(); } } else if (cmd === 'del') { if (modifier === 'exchange') { command = function() {delExchange(Array.prototype.slice.apply(params, [2]));}; } else if (modifier === 'queue') { command = function() {delQueue(Array.prototype.slice.apply(params, [2]));}; } else if (params.length > 2) { command = function() {deleteObject(modifier, params[2], {});}; } else { usage(); } } else if (cmd === 'bind') { command = function() {bind(Array.prototype.slice.apply(params, [1]));}; } else if (cmd === 'unbind') { command = function() {unbind(Array.prototype.slice.apply(params, [1]));}; } else if (cmd === 'reload-acl') { command = function() {reloadAcl();}; } else if (cmd === 'list' && params.length > 1) { command = function() {listObjects(modifier);}; } else { usage(); } } //console.log(config._host); brokerAgent.addConnection(config._host, command); } else { console.error("qpid-config.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/recv.js0000755000175000017500000000461612770711154022612 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proton = require("qpid-proton-messenger"); var address = "amqp://~0.0.0.0"; var message = new proton.Message(); var messenger = new proton.Messenger(); var pumpData = function() { while (messenger.incoming()) { var t = messenger.get(message); console.log("Address: " + message.getAddress()); console.log("Subject: " + message.getSubject()); // body is the body as a native JavaScript Object, useful for most real cases. //console.log("Content: " + message.body); // data is the body as a proton.Data Object, used in this case because // format() returns exactly the same representation as recv.c console.log("Content: " + message.data.format()); messenger.accept(t); } }; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log("Usage: node recv.js (default " + address + ")"); process.exit(0); } address = args[0]; } messenger.setIncomingWindow(1024); messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.recv(); // Receive as many messages as messenger can buffer. messenger.start(); messenger.subscribe(address); } else { console.error("recv.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/send.html0000644000175000017500000000717212770711154023131 0ustar danieldaniel Simple Proton Messenger Send Example

qpid-proton-0.14.0/examples/javascript/messenger/send.js0000755000175000017500000000755212770711154022606 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { // In this example we also set the global variable PROTON_TOTAL_MEMORY in order // to increase the virtual heap available to the emscripten compiled C runtime. // It is not really necessary to do this for this application as the default // value of 16777216 is fine, it is simply done here to illustrate how to do it. PROTON_TOTAL_MEMORY = 50000000; var proton = require("qpid-proton-messenger"); var address = "amqp://0.0.0.0"; var subject = "UK.WEATHER"; var msgtext = "Hello World!"; var tracker = null; var running = true; var message = new proton.Message(); var messenger = new proton.Messenger(); // This is an asynchronous send, so we can't simply call messenger.put(message) // at the end of the application as we would with a synchronous/blocking // version, as the application would simply exit without actually sending. // The following callback function (and messenger.setOutgoingWindow()) // gives us a means to wait until the consumer has received the message before // exiting. The recv.js example explicitly accepts messages it receives. var pumpData = function() { var status = messenger.status(tracker); if (status != proton.Status.PENDING) { if (running) { messenger.stop(); running = false; } } if (messenger.isStopped()) { message.free(); messenger.free(); } }; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log("Usage: node send.js [options] [message]"); console.log("Options:"); console.log(" -a The target address [amqp[s]://domain[/name]] (default " + address + ")"); console.log(" -s The message subject (default " + subject + ")"); console.log("message A text string to send."); process.exit(0); } for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg.charAt(0) === '-') { i++; var val = args[i]; if (arg === '-a') { address = val; } else if (arg === '-s') { subject = val; } } else { msgtext = arg; } } } console.log("Address: " + address); console.log("Subject: " + subject); console.log("Content: " + msgtext); messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.setOutgoingWindow(1024); // So we can track status of send message. messenger.start(); message.setAddress(address); message.setSubject(subject); message.body = msgtext; tracker = messenger.put(message); } else { console.error("send.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/server.js0000755000175000017500000000530412770711154023154 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Simple server for use with client.js illustrating request/response // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proton = require("qpid-proton-messenger"); var address = "amqp://~0.0.0.0"; var message = new proton.Message(); var reply = new proton.Message(); var messenger = new proton.Messenger(); var dispatch = function(request, response) { var subject = request.getSubject(); if (subject) { response.setSubject('Re: ' + subject); } response.properties = request.properties console.log("Dispatched " + subject + " " + JSON.stringify(request.properties)); }; var pumpData = function() { while (messenger.incoming()) { var t = messenger.get(message); var replyTo = message.getReplyTo(); if (replyTo) { console.log(replyTo); reply.setAddress(replyTo); reply.setCorrelationID(message.getCorrelationID()); reply.body = message.body; dispatch(message, reply); messenger.put(reply); } messenger.accept(t); } }; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log("Usage: node server.js (default " + address + ")"); process.exit(0); } address = args[0]; } messenger.setIncomingWindow(1024); messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.recv(); // Receive as many messages as messenger can buffer. messenger.start(); messenger.subscribe(address); } else { console.error("server.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/spout.js0000755000175000017500000000414312770711154023020 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proton = require("qpid-proton-messenger"); console.log("spout not implemented yet"); process.exit(0); var address = "amqp://0.0.0.0"; var subject = "UK.WEATHER"; var msgtext = "Hello World!"; var tracker = null; var running = true; var message = new proton.Message(); var messenger = new proton.Messenger(); function pumpData() { var status = messenger.status(tracker); if (status != proton.Status.PENDING) { console.log("status = " + status); if (running) { console.log("stopping"); messenger.stop(); running = false; } } if (messenger.isStopped()) { console.log("exiting"); message.free(); messenger.free(); } }; messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.setOutgoingWindow(1024); messenger.start(); message.setAddress(address); message.setSubject(subject); message.body = msgtext; tracker = messenger.put(message); } else { console.error("spout.js should be run in Node.js"); } qpid-proton-0.14.0/examples/javascript/messenger/ws2tcp.js0000644000175000017500000001171312770711154023066 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /** * ws2tcp.js is a simple node.js library that proxies from a WebSocket to a TCP * Socket or vice versa. It has minimal dependencies - the standard node.js net * library and the ws WebSocket library (npm install ws). *

* Two fuctions are exported, ws2tcp proxies from a WebSocket to a TCP Socket and * tcp2ws proxies from a TCP Socket to a WebSocket. * @Author Fraser Adams * @file */ var WebSocket = require('ws'); var net = require('net'); /** * This function is shared by ws2tcp and tcp2ws and takes care of cleaning up * and closing the WebSocket and Socket when things close down or error. * @param sock the TCP Socket instance we're registering cleanup handlers for. * @param ws the WebSocket instance we're registering cleanup handlers for. */ var registerCleanupCallbacks = function(sock, ws) { var cleanup = function(sock, ws) { sock.removeAllListeners('close'); sock.end(); ws.removeAllListeners('close'); ws.close(); }; sock.on('close', function() { cleanup(sock, ws); }); sock.on('error', function (e) { console.log("socket error: " + e.code); cleanup(sock, ws); }); ws.on('close', function() { cleanup(sock, ws); }); ws.on('error', function (e) { console.log("websocket error: " + e.code); cleanup(sock, ws); }); }; /** * This function establishes a proxy that listens on a specified TCP Socket port * and proxies data to a WebSocket on the target host listening on the specified * target port. * @param lport the listen port. * @param thost the target host. * @param tport the target port. * @param subProtocols a string containing a comma separated list of WebSocket sub-protocols. */ var tcp2ws = function(lport, thost, tport, subProtocols) { var opts = null; if (subProtocols) { // The regex trims the string (removes spaces at the beginning and end, // then splits the string by , into an Array. subProtocols = subProtocols.replace(/^ +| +$/g,"").split(/ *, */); opts = {'protocol': subProtocols.toString()}; } var server = net.createServer(function(sock) { var url = 'ws://' + thost + ':' + tport; var ws = new WebSocket(url, opts); var ready = false; var buffer = []; registerCleanupCallbacks(sock, ws); sock.on('data', function(data) { if (ready) { ws.send(data); } else { buffer.push(data); } }); ws.on('open', function () { if (buffer.length > 0) { ws.send(Buffer.concat(buffer)); } ready = true; buffer = null; }); ws.on('message', function(m) { sock.write(m); }); }); server.listen(lport); }; /** * This function establishes a proxy that listens on a specified WebSocket port * and proxies data to a TCP Socket on the target host listening on the specified * target port. * @param lport the listen port. * @param thost the target host. * @param tport the target port. */ var ws2tcp = function(lport, thost, tport) { var server = new WebSocket.Server({port: lport}); server.on('connection', function(ws) { var sock = net.connect(tport, thost); var ready = false; var buffer = []; registerCleanupCallbacks(sock, ws); ws.on('message', function(m) { if (ready) { sock.write(m); } else { buffer.push(m); } }); sock.on('connect', function() { if (buffer.length > 0) { sock.write(Buffer.concat(buffer)); } ready = true; buffer = null; }); sock.on('data', function(data) { try { ws.send(data); } catch (e) { console.log("error sending: " + e); } }); }); server.on('error', function(e) { console.log("websocket server error: " + e.code); }); }; // Export the two proxy functions. module.exports.ws2tcp = ws2tcp; module.exports.tcp2ws = tcp2ws; qpid-proton-0.14.0/examples/perl/0000755000175000017500000000000012770711154016107 5ustar danieldanielqpid-proton-0.14.0/examples/perl/messenger/0000755000175000017500000000000012770711154020077 5ustar danieldanielqpid-proton-0.14.0/examples/perl/messenger/async.pm0000644000175000017500000000544712770711154021564 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use qpid_proton; package async::CallbackAdapter; sub new { my ($class) = @_; my ($self) = {}; my $messenger = $_[1]; $self->{_messenger} = $messenger; $messenger->set_blocking(0); $messenger->set_incoming_window(1024); $messenger->set_outgoing_window(1024); my $message = qpid::proton::Message->new(); $self->{_message} = $message; $self->{_incoming} = $message; $self->{_tracked} = {}; bless $self, $class; return $self; } sub run { my ($self) = @_; $self->{_running} = 1; my $messenger = $self->{_messenger}; $messenger->start(); $self->on_start(); do { $messenger->work; $self->process_outgoing; $self->process_incoming; } while($self->{_running}); $messenger->stop(); while(!$messenger->stopped()) { $messenger->work; $self->process_outgoing; $self->process_incoming; } $self->on_stop(); } sub stop { my ($self) = @_; $self->{_running} = 0; } sub process_outgoing { my ($self) = @_; my $tracked = $self->{_tracked}; foreach $key (keys %{$tracked}) { my $on_status = $tracked->{$key}; if (defined($on_status)) { if (!($on_status eq qpid::proton::Tracker::PENDING)) { $self->$on_status($status); $self->{_messenger}->settle($t); # delete the settled item undef $tracked->{$key}; } } } } sub process_incoming { my ($self) = @_; my $messenger = $self->{_messenger}; while ($messenger->incoming > 0) { my $message = $self->{_message}; my $t = $messenger->get($message); $self->on_receive($message); $messenger->accept($t); } } sub send { my ($self) = @_; my $messenger = $self->{_messenger}; my $tracked = $self->{_tracked}; my $message = $_[1]; my $on_status = $_[2] || undef; my $tracker = $messenger->put($message); $tracked->{$tracker} = $on_status if (defined($on_status)); } 1; qpid-proton-0.14.0/examples/perl/messenger/client.pl0000755000175000017500000000446212770711154021723 0ustar danieldaniel#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use strict; use warnings; use Getopt::Long; use Pod::Usage; use qpid_proton; my $reply_to = "~/replies"; my $help = 0; my $man = 0; GetOptions( "reply_to=s", \$reply_to, man => \$man, "help|?" => \$help ) or pod2usage(2); pod2usage(1) if $help; pod2usage(-exitval => 0, -verbose => 2) if $man; # get the address to use and show help if it's missing my $address = $ARGV[0]; pod2usage(1) if !$address; my $messenger = new qpid::proton::Messenger(); $messenger->start; my $message = new qpid::proton::Message(); $message->set_address($address); $message->set_reply_to($reply_to); $message->set_subject("Subject"); $message->set_content("Yo!"); print "Sending to: $address\n"; $messenger->put($message); $messenger->send; if($reply_to =~ /^~\//) { print "Waiting on returned message.\n"; $messenger->receive(1); $messenger->get($message); print $message->get_address . " " . $message->get_subject . "\n"; } $messenger->stop; __END__ =head1 NAME client - Proton example application for Perl. =head1 SYNOPSIS client.pl [OPTIONS]

Options: --reply_to - The reply to address to be used. (default: ~/replies) --help - This help message. --man - Show the full docementation. =over 8 =item B<--reply_to> Specifies the reply address to be used for responses from the server. =item B<--help> Prints a brief help message and exits. =item B<--man> Prints the man page and exits. =back =head2 ADDRESS The form an address takes is: [amqp://][/name] =cut qpid-proton-0.14.0/examples/perl/messenger/recv.pl0000755000175000017500000000546512770711154021410 0ustar danieldaniel#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use warnings; use Scalar::Util qw(reftype); use Data::Dumper; use qpid_proton; sub usage { exit(0); } my @addresses = @ARGV; @addresses = ("~0.0.0.0") unless $addresses[0]; my $messenger = new qpid::proton::Messenger(); my $msg = new qpid::proton::Message(); $messenger->start(); foreach (@addresses) { print "Subscribing to $_\n"; $messenger->subscribe($_); } for(;;) { $messenger->receive(10); while ($messenger->incoming() > 0) { $messenger->get($msg); print "\n"; print "Address: " . $msg->get_address() . "\n"; print "Subject: " . $msg->get_subject() . "\n" unless !defined($msg->get_subject()); print "Body: "; my $body = $msg->get_body(); my $body_type = $msg->get_body_type(); if (!defined($body_type)) { print "The body type wasn't defined!\n"; } elsif ($body_type == qpid::proton::BOOL) { print "[BOOL]\n"; print "" . ($body ? "TRUE" : "FALSE") . "\n"; } elsif ($body_type == qpid::proton::MAP) { print "[HASH]\n"; print Dumper(\%{$body}) . "\n"; } elsif ($body_type == qpid::proton::ARRAY) { print "[ARRAY]\n"; print Data::Dumper->Dump($body) . "\n"; } elsif ($body_type == qpid::proton::LIST) { print "[LIST]\n"; print Data::Dumper->Dump($body) . "\n"; } else { print "[$body_type]\n"; print "$body\n"; } print "Properties:\n"; my $props = $msg->get_properties(); foreach (keys $props) { print "\t$_=$props->{$_}\n"; } print "Instructions:\n"; my $instructions = $msg->get_instructions; foreach (keys $instructions) { print "\t$_=" . $instructions->{$_} . "\n"; } print "Annotations:\n"; my $annotations = $msg->get_annotations(); foreach (keys $annotations) { print "\t$_=" . $annotations->{$_} . "\n"; } } } die $@ if ($@); qpid-proton-0.14.0/examples/perl/messenger/recv_async.pl0000755000175000017500000000400612770711154022573 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use qpid_proton; use async; package async::Receiver; @ISA = (async::CallbackAdapter); sub on_start { my ($self) = @_; my $args = $_[1] || ("amqp://~0.0.0.0"); my $messenger = $self->{_messenger}; foreach $arg ($args) { $messenger->subscribe($arg); } $messenger->receive(); } sub on_receive { my ($self) = @_; my $msg = $_[1]; my $message = $self->{_message}; my $text = ""; if (defined($msg->get_body)) { $text = $msg->get_body; if ($text eq "die") { $self->stop; } } else { $text = $message->get_subject; } $text = "" if (!defined($text)); print "Received: $text\n"; if ($msg->get_reply_to) { print "Sending reply to: " . $msg->get_reply_to . "\n"; $message->clear; $message->set_address($msg->get_reply_to()); $message->set_body("Reply for ", $msg->get_body); $self->send($message); } } sub on_status { my ($self) = @_; my $messenger = $self->{_messenger}; my $status = $_[1]; print "Status: ", $status, "\n"; } sub on_stop { print "Stopped.\n" } package main; our $messenger = new qpid::proton::Messenger(); our $app = new async::Receiver($messenger); $app->run(); qpid-proton-0.14.0/examples/perl/messenger/send.pl0000755000175000017500000000532412770711154021374 0ustar danieldaniel#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use strict; use warnings; use Getopt::Std; use qpid_proton; $Getopt::Std::STANDARD_HELP_VERSION = 1; sub VERSION_MESSAGE() { } sub HELP_MESSAGE() { print "Usage: send.pl [OPTIONS] -a
\n"; print "Options:\n"; print "\t-s - the message subject\n"; print "\t-C - the message content\n"; print "\t
- amqp://[/]\n"; print "\t-h - this message\n"; exit; } my %options = (); getopts("a:C:s:h:", \%options) or HELP_MESSAGE(); my $address = $options{a} || "amqp://0.0.0.0"; my $subject = $options{s} || localtime(time); my $content = $options{C} || ""; my $msg = new qpid::proton::Message(); my $messenger = new qpid::proton::Messenger(); $messenger->start(); my @messages = @ARGV; @messages = ("This is a test. " . localtime(time)) unless $messages[0]; foreach (@messages) { $msg->set_address($address); $msg->set_subject($subject); $msg->set_body($content); # try a few different body types my $body_type = int(rand(6)); $msg->set_property("sent", "" . localtime(time)); $msg->get_instructions->{"fold"} = "yes"; $msg->get_instructions->{"spindle"} = "no"; $msg->get_instructions->{"mutilate"} = "no"; $msg->get_annotations->{"version"} = 1.0; $msg->get_annotations->{"pill"} = "RED"; SWITCH: { $body_type == 0 && do { $msg->set_body("It is now " . localtime(time));}; $body_type == 1 && do { $msg->set_body(rand(65536)); }; $body_type == 2 && do { $msg->set_body(int(rand(2)), qpid::proton::BOOL); }; $body_type == 3 && do { $msg->set_body({"foo" => "bar"}); }; $body_type == 4 && do { $msg->set_body([4, [1, 2, 3.1, 3.4E-5], 8, 15, 16, 23, 42]); }; $body_type == 5 && do { $msg->set_body(int(rand(65535))); } } $messenger->put($msg); print "Sent: " . $msg->get_body . " [CONTENT TYPE: " . $msg->get_body_type . "]\n"; } $messenger->send(); $messenger->stop(); die $@ if ($@); qpid-proton-0.14.0/examples/perl/messenger/send_async.pl0000644000175000017500000000457512770711154022575 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use Getopt::Std; use qpid_proton; use async; $Getopt::Std::STANDARD_HELP_VERSION = 1; sub VERSION_MESSAGE() {} sub HELP_MESSAGE() { print "Usage: send_async.pl [OPTIONS] ...\n"; print "Options:\n"; print "\t-a - the message address (def. amqp://0.0.0.0)\n"; print "\t-r - the reply-to address: //[/]\n"; print "\t msg_# - a text string to send\n"; } my %optons = (); getopts("a:r:", \%options) or usage(); our $address = $options{a} || "amqp://0.0.0.0"; our $replyto = $options{r} || "~/#"; package async::Sender; @ISA = (async::CallbackAdapter); sub on_start { my ($self) = @_; my $message = $self->{_message}; my $messenger = $self->{_messenger}; my $args = $_[1] || ("Hello world!"); print "Started\n"; $message->clear; $message->set_address("amqp://0.0.0.0"); $message->set_reply_to($replyto) if (defined($replyto)); foreach $arg ($args) { $message->set_body($arg); if ($replyto) { $message->set_reply_to($replyto); } $self->send($message, "on_status"); } $messenger->receive() if (defined($replyto)); } sub on_status { my ($self) = @_; my $messenger = $self->{_messenger}; my $status = $_[1] || ""; print "Status: ", $status, "\n"; } sub on_receive { my ($self) = @_; my $message = $_[1]; my $text = $message->get_body || "[empty]"; print "Received: " . $text . "\n"; $self->stop(); } sub on_stop { print "Stopped\n"; } package main; our $msgr = new qpid::proton::Messenger(); our $app = async::Sender->new($msgr); $app->run; qpid-proton-0.14.0/examples/perl/messenger/server.pl0000755000175000017500000000541212770711154021747 0ustar danieldaniel#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # use strict; use warnings; use Getopt::Long; use Pod::Usage; use qpid_proton; my $help = 0; my $man = 0; GetOptions( man => \$man, "help|?" => \$help ) or pod2usage(2); pod2usage(1) if $help; pod2usage(-exitval => 0, -verbose => 2) if $man; pod2usage(2) unless scalar(@ARGV); # create a messenger for receiving and holding # incoming messages our $messenger = new qpid::proton::Messenger; $messenger->start; # subscribe the messenger to all addresses specified sources foreach (@ARGV) { $messenger->subscribe($_); } sub dispatch { my $request = $_[0]; my $reply = $_[1]; if ($request->get_subject) { $reply->set_subject("Re: " . $request->get_subject); } $reply->set_properties($request->get_properties); print "Dispatched " . $request->get_subject . "\n"; my $properties = $request->get_properties; foreach (keys %{$properties}) { my $value = $properties->{%_}; print "\t$_: $value\n"; } } our $message = new qpid::proton::Message; our $reply = new qpid::proton::Message; while(1) { $messenger->receive(1) if $messenger->incoming < 10; if ($messenger->incoming > 0) { $messenger->get($message); if ($message->get_reply_to) { print $message->get_reply_to . "\n"; $reply->set_address($message->get_reply_to); $reply->set_correlation_id($message->get_correlation_id); $reply->set_body($message->get_body); } dispatch($message, $reply); $messenger->put($reply); $messenger->send; } } $message->stop; __END__ =head1 NAME server - Proton example server application for Perl. =head1 SYNOPSIS server.pl [OPTIONS] ... Options: --help - This help message. --man - Show the full documentation. =over 8 =item B<--help> Prints a brief help message and exits. =item B<--man> Prints the man page and exits. =back =head2 ADDRESS The form an address takes is: [amqp://][/name] =cut qpid-proton-0.14.0/examples/php/0000755000175000017500000000000012770711154015734 5ustar danieldanielqpid-proton-0.14.0/examples/php/messenger/0000755000175000017500000000000012770711154017724 5ustar danieldanielqpid-proton-0.14.0/examples/php/messenger/recv.php0000644000175000017500000000234612770711154021401 0ustar danieldanielstart(); if ($argv[1]) { $mess->subscribe($argv[1]); } else { $mess->subscribe("amqp://~0.0.0.0"); } $msg = new Message(); while (true) { $mess->recv(10); while ($mess->incoming) { try { $mess->get($msg); } catch (Exception $e) { print "$e\n"; continue; } print "$msg->address, $msg->subject, $msg->body\n"; } } $mess->stop(); ?> qpid-proton-0.14.0/examples/php/messenger/send.php0000644000175000017500000000217212770711154021370 0ustar danieldanielstart(); $msg = new Message(); if ($argv[1]) { $msg->address = $argv[1]; } else { $msg->address = "amqp://0.0.0.0"; } $msg->subject = "Hello World!"; $msg->body = "this is a test"; $mess->put($msg); $mess->send(); print "sent: $msg->subject\n"; $mess->stop(); ?> qpid-proton-0.14.0/examples/python/0000755000175000017500000000000012770711154016466 5ustar danieldanielqpid-proton-0.14.0/examples/python/abstract_server.py0000755000175000017500000000235512770711154022241 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton_server import Server class Application(Server): def __init__(self, host, address): super(Application, self).__init__(host, address) def on_request(self, request, reply_to): response = request.upper() self.send(response, reply_to) print("Request from: %s" % reply_to) try: Application("localhost:5672", "examples").run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/broker.py0000755000175000017500000001027512770711154020334 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import collections, optparse from proton import Endpoint, generate_uuid from proton.handlers import MessagingHandler from proton.reactor import Container class Queue(object): def __init__(self, dynamic=False): self.dynamic = dynamic self.queue = collections.deque() self.consumers = [] def subscribe(self, consumer): self.consumers.append(consumer) def unsubscribe(self, consumer): if consumer in self.consumers: self.consumers.remove(consumer) return len(self.consumers) == 0 and (self.dynamic or self.queue.count == 0) def publish(self, message): self.queue.append(message) self.dispatch() def dispatch(self, consumer=None): if consumer: c = [consumer] else: c = self.consumers while self._deliver_to(c): pass def _deliver_to(self, consumers): try: result = False for c in consumers: if c.credit: c.send(self.queue.popleft()) result = True return result except IndexError: # no more messages return False class Broker(MessagingHandler): def __init__(self, url): super(Broker, self).__init__() self.url = url self.queues = {} def on_start(self, event): self.acceptor = event.container.listen(self.url) def _queue(self, address): if address not in self.queues: self.queues[address] = Queue() return self.queues[address] def on_link_opening(self, event): if event.link.is_sender: if event.link.remote_source.dynamic: address = str(generate_uuid()) event.link.source.address = address q = Queue(True) self.queues[address] = q q.subscribe(event.link) elif event.link.remote_source.address: event.link.source.address = event.link.remote_source.address self._queue(event.link.source.address).subscribe(event.link) elif event.link.remote_target.address: event.link.target.address = event.link.remote_target.address def _unsubscribe(self, link): if link.source.address in self.queues and self.queues[link.source.address].unsubscribe(link): del self.queues[link.source.address] def on_link_closing(self, event): if event.link.is_sender: self._unsubscribe(event.link) def on_connection_closing(self, event): self.remove_stale_consumers(event.connection) def on_disconnected(self, event): self.remove_stale_consumers(event.connection) def remove_stale_consumers(self, connection): l = connection.link_head(Endpoint.REMOTE_ACTIVE) while l: if l.is_sender: self._unsubscribe(l) l = l.next(Endpoint.REMOTE_ACTIVE) def on_sendable(self, event): self._queue(event.link.source.address).dispatch(event.link) def on_message(self, event): self._queue(event.link.target.address).publish(event.message) parser = optparse.OptionParser(usage="usage: %prog [options]") parser.add_option("-a", "--address", default="localhost:5672", help="address router listens on (default %default)") opts, args = parser.parse_args() try: Container(Broker(opts.address)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/client_http.py0000755000175000017500000000726012770711154021365 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import tornado.ioloop import tornado.web from proton import Message from proton.handlers import MessagingHandler from proton_tornado import Container class Client(MessagingHandler): def __init__(self, host, address): super(Client, self).__init__() self.host = host self.address = address self.sent = [] self.pending = [] self.reply_address = None self.sender = None self.receiver = None def on_start(self, event): conn = event.container.connect(self.host) self.sender = event.container.create_sender(conn, self.address) self.receiver = event.container.create_receiver(conn, None, dynamic=True) def on_link_opened(self, event): if event.receiver == self.receiver: self.reply_address = event.link.remote_source.address self.do_request() def on_sendable(self, event): self.do_request() def on_message(self, event): if self.sent: request, handler = self.sent.pop(0) print("%s => %s" % (request, event.message.body)) handler(event.message.body) self.do_request() def do_request(self): if self.pending and self.reply_address and self.sender.credit: request, handler = self.pending.pop(0) self.sent.append((request, handler)) req = Message(reply_to=self.reply_address, body=request) self.sender.send(req) def request(self, body, handler): self.pending.append((body, handler)) self.do_request() self.container.touch() class ExampleHandler(tornado.web.RequestHandler): def initialize(self, client): self.client = client def get(self): self._write_open() self._write_form() self._write_close() @tornado.web.asynchronous def post(self): client.request(self.get_body_argument("message"), lambda x: self.on_response(x)) def on_response(self, body): self.set_header("Content-Type", "text/html") self._write_open() self._write_form() self.write("Response: " + body) self._write_close() self.finish() def _write_open(self): self.write('') def _write_close(self): self.write('') def _write_form(self): self.write('
' 'Request: ' '' '
') loop = tornado.ioloop.IOLoop.instance() client = Client("localhost:5672", "examples") client.container = Container(client, loop=loop) client.container.initialise() app = tornado.web.Application([tornado.web.url(r"/client", ExampleHandler, dict(client=client))]) app.listen(8888) try: loop.start() except KeyboardInterrupt: loop.stop() qpid-proton-0.14.0/examples/python/db_common.py0000755000175000017500000000740712770711154021010 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # try: import Queue except: import queue as Queue import sqlite3 import threading class Db(object): def __init__(self, db, injector): self.db = db self.injector = injector self.tasks = Queue.Queue() self.position = None self.pending_events = [] self.running = True self.thread = threading.Thread(target=self._process) self.thread.daemon=True self.thread.start() def close(self): self.tasks.put(lambda conn: self._close()) def reset(self): self.tasks.put(lambda conn: self._reset()) def load(self, records, event=None): self.tasks.put(lambda conn: self._load(conn, records, event)) def get_id(self, event): self.tasks.put(lambda conn: self._get_id(conn, event)) def insert(self, id, data, event=None): self.tasks.put(lambda conn: self._insert(conn, id, data, event)) def delete(self, id, event=None): self.tasks.put(lambda conn: self._delete(conn, id, event)) def _reset(self, ignored=None): self.position = None def _close(self, ignored=None): self.running = False def _get_id(self, conn, event): cursor = conn.execute("SELECT * FROM records ORDER BY id DESC") row = cursor.fetchone() if event: if row: event.id = row['id'] else: event.id = 0 self.injector.trigger(event) def _load(self, conn, records, event): if self.position: cursor = conn.execute("SELECT * FROM records WHERE id > ? ORDER BY id", (self.position,)) else: cursor = conn.execute("SELECT * FROM records ORDER BY id") while not records.full(): row = cursor.fetchone() if row: self.position = row['id'] records.put(dict(row)) else: break if event: self.injector.trigger(event) def _insert(self, conn, id, data, event): if id: conn.execute("INSERT INTO records(id, description) VALUES (?, ?)", (id, data)) else: conn.execute("INSERT INTO records(description) VALUES (?)", (data,)) if event: self.pending_events.append(event) def _delete(self, conn, id, event): conn.execute("DELETE FROM records WHERE id=?", (id,)) if event: self.pending_events.append(event) def _process(self): conn = sqlite3.connect(self.db) conn.row_factory = sqlite3.Row with conn: while self.running: f = self.tasks.get(True) try: while True: f(conn) f = self.tasks.get(False) except Queue.Empty: pass conn.commit() for event in self.pending_events: self.injector.trigger(event) self.pending_events = [] self.injector.close() qpid-proton-0.14.0/examples/python/db_ctrl.py0000755000175000017500000000336412770711154020462 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sqlite3 import sys if len(sys.argv) < 3: print("Usage: %s [init|insert|list] db" % sys.argv[0]) else: conn = sqlite3.connect(sys.argv[2]) with conn: if sys.argv[1] == "init": conn.execute("DROP TABLE IF EXISTS records") conn.execute("CREATE TABLE records(id INTEGER PRIMARY KEY AUTOINCREMENT, description TEXT)") conn.commit() elif sys.argv[1] == "list": cursor = conn.cursor() cursor.execute("SELECT * FROM records") rows = cursor.fetchall() for r in rows: print(r) elif sys.argv[1] == "insert": while True: l = sys.stdin.readline() if not l: break conn.execute("INSERT INTO records(description) VALUES (?)", (l.rstrip(),)) conn.commit() else: print("Unrecognised command: %s" % sys.argv[1]) qpid-proton-0.14.0/examples/python/db_recv.py0000755000175000017500000000550412770711154020453 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import optparse from proton.handlers import MessagingHandler from proton.reactor import ApplicationEvent, Container, EventInjector from db_common import Db class Recv(MessagingHandler): def __init__(self, url, count): super(Recv, self).__init__(auto_accept=False) self.url = url self.delay = 0 self.last_id = None self.expected = count self.received = 0 self.accepted = 0 self.db = Db("dst_db", EventInjector()) def on_start(self, event): event.container.selectable(self.db.injector) e = ApplicationEvent("id_loaded") e.container = event.container self.db.get_id(e) def on_id_loaded(self, event): self.last_id = event.id event.container.create_receiver(self.url) def on_record_inserted(self, event): self.accept(event.delivery) self.accepted += 1 if self.accepted == self.expected: event.connection.close() self.db.close() def on_message(self, event): id = int(event.message.id) if (not self.last_id) or id > self.last_id: if self.received < self.expected: self.received += 1 self.last_id = id self.db.insert(id, event.message.body, ApplicationEvent("record_inserted", delivery=event.delivery)) print("inserted message %s" % id) else: self.release(event.delivery) else: self.accept(event.delivery) parser = optparse.OptionParser(usage="usage: %prog [options]") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address from which messages are received (default %default)") parser.add_option("-m", "--messages", type="int", default=0, help="number of messages to receive; 0 receives indefinitely (default %default)") opts, args = parser.parse_args() try: Container(Recv(opts.address, opts.messages)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/direct_recv.py0000755000175000017500000000421512770711154021336 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import optparse from proton.handlers import MessagingHandler from proton.reactor import Container class Recv(MessagingHandler): def __init__(self, url, count): super(Recv, self).__init__() self.url = url self.expected = count self.received = 0 def on_start(self, event): self.acceptor = event.container.listen(self.url) def on_message(self, event): if event.message.id and event.message.id < self.received: # ignore duplicate message return if self.expected == 0 or self.received < self.expected: print(event.message.body) self.received += 1 if self.received == self.expected: event.receiver.close() event.connection.close() self.acceptor.close() parser = optparse.OptionParser(usage="usage: %prog [options]") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address from which messages are received (default %default)") parser.add_option("-m", "--messages", type="int", default=100, help="number of messages to receive; 0 receives indefinitely (default %default)") opts, args = parser.parse_args() try: Container(Recv(opts.address, opts.messages)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/helloworld_blocking.py0000755000175000017500000000231312770711154023065 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import Message from proton.utils import BlockingConnection from proton.handlers import IncomingMessageHandler conn = BlockingConnection("localhost:5672") receiver = conn.create_receiver("examples") sender = conn.create_sender("examples") sender.send(Message(body="Hello World!")); msg = receiver.receive(timeout=30) print(msg.body) receiver.accept() conn.close() qpid-proton-0.14.0/examples/python/helloworld_direct_tornado.py0000755000175000017500000000311612770711154024277 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import Message from proton.handlers import MessagingHandler from proton_tornado import Container class HelloWorld(MessagingHandler): def __init__(self, url): super(HelloWorld, self).__init__() self.url = url def on_start(self, event): self.acceptor = event.container.listen(self.url) event.container.create_sender(self.url) def on_sendable(self, event): event.sender.send(Message(body="Hello World!")) event.sender.close() def on_message(self, event): print(event.message.body) def on_accepted(self, event): event.connection.close() def on_connection_closed(self, event): self.acceptor.close() Container(HelloWorld("localhost:8888/examples")).run() qpid-proton-0.14.0/examples/python/helloworld_tornado.py0000755000175000017500000000312612770711154022746 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import Message from proton.handlers import MessagingHandler from proton_tornado import Container class HelloWorld(MessagingHandler): def __init__(self, server, address): super(HelloWorld, self).__init__() self.server = server self.address = address def on_start(self, event): conn = event.container.connect(self.server) event.container.create_receiver(conn, self.address) event.container.create_sender(conn, self.address) def on_sendable(self, event): event.sender.send(Message(body="Hello World!")) event.sender.close() def on_message(self, event): print(event.message.body) event.connection.close() Container(HelloWorld("localhost:5672", "examples")).run() qpid-proton-0.14.0/examples/python/messenger/0000755000175000017500000000000012770711154020456 5ustar danieldanielqpid-proton-0.14.0/examples/python/messenger/README.txt0000644000175000017500000000116212770711154022154 0ustar danieldanielThis directory contains example scripts using the messenger API. send.py - a simple example of using the messenger API to send messages recv.py - a simple example of using the messenger API to receive messages Note that depending on the address passed into these scripts, you can use them in either a peer to peer or a brokered scenario. For brokered usage: recv.py amqp:/// send.py -a amqp:/// msg_1 ... msg_n For peer to peer usage: # execute on to receive messages from all local network interfaces recv.py amqp://~0.0.0.0 send.py -a amqp:// msg_1 ... msg_n qpid-proton-0.14.0/examples/python/messenger/async.py0000755000175000017500000000475712770711154022165 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys from proton import * class CallbackAdapter: def __init__(self, messenger): self.messenger = messenger self.messenger.blocking = False self.messenger.outgoing_window = 1024 self.messenger.incoming_window = 1024 # for application use self.message = Message() self._incoming_message = Message() self.tracked = {} def run(self): self.running = True self.messenger.start() self.on_start() while self.running: self.messenger.work() self._process() self.messenger.stop() while not self.messenger.stopped: self.messenger.work() self._process() self.on_stop() def stop(self): self.running = False def _process(self): self._process_outgoing() self._process_incoming() def _process_outgoing(self): for t, on_status in list(self.tracked.items()): status = self.messenger.status(t) if status != PENDING: on_status(status) self.messenger.settle(t) del self.tracked[t] def _process_incoming(self): while self.messenger.incoming: t = self.messenger.get(self._incoming_message) try: self.on_recv(self._incoming_message) self.messenger.accept(t) except: ex = sys.exc_info()[1] print("Exception:", ex) self.messenger.reject(t) def send(self, message, on_status=None): t = self.messenger.put(message) if on_status: self.tracked[t] = on_status qpid-proton-0.14.0/examples/python/messenger/client.py0000755000175000017500000000307312770711154022314 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from proton import * parser = optparse.OptionParser(usage="usage: %prog ", description="simple message server") parser.add_option("-r", "--reply_to", default="~/replies", help="address: [amqp://][/] (default %default)") opts, args = parser.parse_args() if len(args) != 2: parser.error("incorrect number of arguments") address, subject = args mng = Messenger() mng.start() msg = Message() msg.address = address msg.subject = subject msg.reply_to = opts.reply_to mng.put(msg) mng.send() if opts.reply_to[:2] == "~/": mng.recv(1) try: mng.get(msg) print(msg.address, msg.subject) except Exception as e: print(e) mng.stop() qpid-proton-0.14.0/examples/python/messenger/recv.py0000755000175000017500000000331512770711154021774 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from proton import * parser = optparse.OptionParser(usage="usage: %prog [options] ... ", description="simple message receiver") parser.add_option("-c", "--certificate", help="path to certificate file") parser.add_option("-k", "--private-key", help="path to private key file") parser.add_option("-p", "--password", help="password for private key file") opts, args = parser.parse_args() if not args: args = ["amqp://~0.0.0.0"] mng = Messenger() mng.certificate=opts.certificate mng.private_key=opts.private_key mng.password=opts.password mng.start() for a in args: mng.subscribe(a) msg = Message() while True: mng.recv() while mng.incoming: try: mng.get(msg) except Exception as e: print(e) else: print(msg.address, msg.subject or "(no subject)", msg.properties, msg.body) mng.stop() qpid-proton-0.14.0/examples/python/messenger/recv_async.py0000755000175000017500000000335212770711154023172 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from async import * parser = optparse.OptionParser(usage="usage: %prog [options] ... ", description="simple message receiver") opts, args = parser.parse_args() if not args: args = ["amqp://~0.0.0.0"] class App(CallbackAdapter): def on_start(self): print("Started") for a in args: print("Subscribing to:", a) self.messenger.subscribe(a) self.messenger.recv() def on_recv(self, msg): print("Received:", msg) if msg.body == "die": self.stop() if msg.reply_to: self.message.clear() self.message.address = msg.reply_to self.message.body = "Reply for: %s" % msg.body print("Replied:", self.message) self.send(self.message) def on_stop(self): print("Stopped") a = App(Messenger()) a.run() qpid-proton-0.14.0/examples/python/messenger/send.py0000755000175000017500000000263012770711154021765 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from proton import * parser = optparse.OptionParser(usage="usage: %prog [options] ... ", description="simple message sender") parser.add_option("-a", "--address", default="amqp://0.0.0.0", help="address: //[/] (default %default)") opts, args = parser.parse_args() if not args: args = ["Hello World!"] mng = Messenger() mng.start() msg = Message() for m in args: msg.address = opts.address msg.body = str(m) mng.put(msg) mng.send() print("sent:", ", ".join(args)) mng.stop() qpid-proton-0.14.0/examples/python/messenger/send_async.py0000755000175000017500000000412412770711154023162 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from async import * parser = optparse.OptionParser(usage="usage: %prog [options] ... ", description="simple message sender") parser.add_option("-a", "--address", default="amqp://0.0.0.0", help="address: //[/] (default %default)") parser.add_option("-r", "--reply_to", help="reply_to: //[/]") opts, args = parser.parse_args() if not args: args = ["Hello World!"] class App(CallbackAdapter): def on_start(self): print("Started") self.message.clear() self.message.address = opts.address self.message.reply_to = opts.reply_to for a in args: self.message.body = a self.send(self.message, self.on_status) if opts.reply_to: self.messenger.recv() def on_status(self, status): print("Status:", status) if not opts.reply_to or opts.reply_to[0] != "~": args.pop(0) if not args: self.stop() def on_recv(self, msg): print("Received:", msg) if opts.reply_to and opts.reply_to[0] == "~": args.pop(0) if not args: self.stop() def on_stop(self): print("Stopped") a = App(Messenger()) a.run() qpid-proton-0.14.0/examples/python/messenger/server.py0000755000175000017500000000332612770711154022345 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from proton import * parser = optparse.OptionParser(usage="usage: %prog ... ", description="simple message server") opts, args = parser.parse_args() if not args: args = ["amqp://~0.0.0.0"] mng = Messenger() mng.start() for a in args: mng.subscribe(a) def dispatch(request, response): if request.subject: response.subject = "Re: %s" % request.subject response.properties = request.properties print("Dispatched %s %s" % (request.subject, request.properties)) msg = Message() reply = Message() while True: if mng.incoming < 10: mng.recv(10) if mng.incoming > 0: mng.get(msg) if msg.reply_to: print(msg.reply_to) reply.address = msg.reply_to reply.correlation_id = msg.correlation_id reply.body = msg.body dispatch(msg, reply) mng.put(reply) mng.send() mng.stop() qpid-proton-0.14.0/examples/python/queue_browser.py0000755000175000017500000000262312770711154021735 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton.reactor import Container, Copy from proton.handlers import MessagingHandler class Recv(MessagingHandler): def __init__(self): super(Recv, self).__init__() def on_start(self, event): conn = event.container.connect("localhost:5672") event.container.create_receiver(conn, "examples", options=Copy()) def on_message(self, event): print(event.message) if event.receiver.queued == 0 and event.receiver.drained: event.connection.close() try: Container(Recv()).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/reactor/0000755000175000017500000000000012770711154020125 5ustar danieldanielqpid-proton-0.14.0/examples/python/reactor/README.md0000644000175000017500000000147112770711154021407 0ustar danieldanielThe examples in this directory provide a basic introduction to the proton reactor API and are best viewed in the order presented below. The examples contain comments that explain things in a tutorial-style manner. At some point soon this content will be pulled out into a proper tutorial that references the relevant code snippets from these examples. Until then please bear with this clumsy style of presentation. This API is present in C as well and most of these examples will transliterate into C in a fairly straightforward way. - hello-world.py - goodbye-world.py - scheduling.py - counter.py - count-randomly.py - unhandled.py - reactor-logger.py - global-logger.py - delegates.py - handlers.py - echo.py - cat.py - send.py - recv.py - tornado-hello-world.py - tornado-send.py qpid-proton-0.14.0/examples/python/reactor/cat.py0000755000175000017500000000345112770711154021254 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, os from proton.reactor import Reactor class Echo: def __init__(self, source): self.source = source def on_selectable_init(self, event): sel = event.context # XXX: no selectable property yet # We can configure a selectable with any file descriptor we want. sel.fileno(self.source.fileno()) # Ask to be notified when the file is readable. sel.reading = True event.reactor.update(sel) def on_selectable_readable(self, event): sel = event.context # The on_selectable_readable event tells us that there is data # to be read, or the end of stream has been reached. data = os.read(sel.fileno(), 1024) if data: print(data, end=' ') else: sel.terminate() event.reactor.update(sel) class Program: def on_reactor_init(self, event): event.reactor.selectable(Echo(open(sys.argv[1]))) r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/count-randomly.py0000755000175000017500000000535012770711154023460 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time, random from proton.reactor import Reactor # Let's try to modify our counter example. In addition to counting to # 10 in quarter second intervals, let's also print out a random number # every half second. This is not a super easy thing to express in a # purely sequential program, but not so difficult using events. class Counter: def __init__(self, limit): self.limit = limit self.count = 0 def on_timer_task(self, event): self.count += 1 print(self.count) if not self.done(): event.reactor.schedule(0.25, self) # add a public API to check for doneness def done(self): return self.count >= self.limit class Program: def on_reactor_init(self, event): self.start = time.time() print("Hello, World!") # Save the counter instance in an attribute so we can refer to # it later. self.counter = Counter(10) event.reactor.schedule(0.25, self.counter) # Now schedule another event with a different handler. Note # that the timer tasks go to separate handlers, and they don't # interfere with each other. event.reactor.schedule(0.5, self) def on_timer_task(self, event): # keep on shouting until we are done counting print("Yay, %s!" % random.randint(10, 100)) if not self.counter.done(): event.reactor.schedule(0.5, self) def on_reactor_final(self, event): print("Goodbye, World! (after %s long seconds)" % (time.time() - self.start)) # In hello-world.py we said the reactor exits when there are no more # events to process. While this is true, it's not actually complete. # The reactor exits when there are no more events to process and no # possibility of future events arising. For that reason the reactor # will keep running until there are no more scheduled events and then # exit. r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/counter.py0000755000175000017500000000424312770711154022164 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor class Counter: def __init__(self, limit): self.limit = limit self.count = 0 def on_timer_task(self, event): self.count += 1 print(self.count) if self.count < self.limit: # A recurring task can be acomplished by just scheduling # another event. event.reactor.schedule(0.25, self) class Program: def on_reactor_init(self, event): self.start = time.time() print("Hello, World!") # Note that unlike the previous scheduling example, we pass in # a separate object for the handler. This means that the timer # event we just scheduled will not be seen by Program as it is # being handled by the Counter instance we create. event.reactor.schedule(0.25, Counter(10)) def on_reactor_final(self, event): print("Goodbye, World! (after %s long seconds)" % (time.time() - self.start)) # In hello-world.py we said the reactor exits when there are no more # events to process. While this is true, it's not actually complete. # The reactor exits when there are no more events to process and no # possibility of future events arising. For that reason the reactor # will keep running until there are no more scheduled events and then # exit. r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/delegates.py0000755000175000017500000000270612770711154022444 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor # Events know how to dispatch themselves to handlers. By combining # this with on_unhandled, you can provide a kind of inheritance # between handlers using delegation. class Hello: def on_reactor_init(self, event): print("Hello, World!") class Goodbye: def on_reactor_final(self, event): print("Goodbye, World!") class Program: def __init__(self, *delegates): self.delegates = delegates def on_unhandled(self, name, event): for d in self.delegates: event.dispatch(d) r = Reactor(Program(Hello(), Goodbye())) r.run() qpid-proton-0.14.0/examples/python/reactor/echo.py0000755000175000017500000000411712770711154021423 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, os from proton.reactor import Reactor class Echo: def __init__(self, source): self.source = source def on_selectable_init(self, event): sel = event.context # XXX: no selectable property yet # We can configure a selectable with any file descriptor we want. sel.fileno(self.source.fileno()) # Ask to be notified when the file is readable. sel.reading = True event.reactor.update(sel) def on_selectable_readable(self, event): sel = event.context # The on_selectable_readable event tells us that there is data # to be read, or the end of stream has been reached. data = os.read(sel.fileno(), 1024) if data: print(data, end=' ') else: sel.terminate() event.reactor.update(sel) class Program: def on_reactor_init(self, event): # Every selectable is a possible source of future events. Our # selectable stays alive until it reads the end of stream # marker. This will keep the whole reactor running until we # type Control-D. print("Type whatever you want and then use Control-D to exit:") event.reactor.selectable(Echo(sys.stdin)) r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/global-logger.py0000755000175000017500000000374512770711154023230 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor # Not every event goes to the reactor's event handler. If we have a # separate handler for something like a scheduled task, then those # events aren't logged by the logger associated with the reactor's # handler. Sometimes this is useful if you don't want to see them, but # sometimes you want the global picture. class Logger: def on_unhandled(self, name, event): print("LOG:", name, event) class Task: def on_timer_task(self, event): print("Mission accomplished!") class Program: def on_reactor_init(self, event): print("Hello, World!") event.reactor.schedule(0, Task()) def on_reactor_final(self, event): print("Goodbye, World!") r = Reactor(Program()) # In addition to having a regular handler, the reactor also has a # global handler that sees every event. By adding the Logger to the # global handler instead of the regular handler, we can log every # single event that occurs in the system regardless of whether or not # there are specific handlers associated with the objects that are the # target of those events. r.global_handler.add(Logger()) r.run() qpid-proton-0.14.0/examples/python/reactor/goodbye-world.py0000755000175000017500000000352112770711154023260 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton.reactor import Reactor # So far the reactive hello-world doesn't look too different from a # regular old non-reactive hello-world. The on_reactor_init method can # be used roughly as a 'main' method would. A program that only uses # that one event, however, isn't going to be very reactive. By using # other events, we can write a fully reactive program. class Program: # As before we handle the reactor init event. def on_reactor_init(self, event): print("Hello, World!") # In addition to an initial event, the reactor also produces an # event when it is about to exit. This may not behave much # differently than just putting the goodbye print statement inside # on_reactor_init, but as we grow our program, this piece of it # will always be what happens last, and will always happen # regardless of what other paths the main logic of our program # might take. def on_reactor_final(self, event): print("Goodbye, World!") r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/handlers.py0000755000175000017500000000270712770711154022310 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor class World: def on_reactor_init(self, event): print("World!") class Goodbye: def on_reactor_final(self, event): print("Goodbye, World!") class Hello: def __init__(self): # When an event dispatches itself to a handler, it also checks # if that handler has a "handlers" attribute and dispatches # the event to any children. self.handlers = [World(), Goodbye()] # The parent handler always receives the event first. def on_reactor_init(self, event): print("Hello", end=' ') r = Reactor(Hello()) r.run() qpid-proton-0.14.0/examples/python/reactor/hello-world.py0000755000175000017500000000307112770711154022733 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton.reactor import Reactor # The proton reactor provides a general purpose event processing # library for writing reactive programs. A reactive program is defined # by a set of event handlers. An event handler is just any class or # object that defines the "on_" methods that it cares to # handle. class Program: # The reactor init event is produced by the reactor itself when it # starts. def on_reactor_init(self, event): print("Hello, World!") # When you construct a reactor, you give it a handler. r = Reactor(Program()) # When you call run, the reactor will process events. The reactor init # event is what kicks off everything else. When the reactor has no # more events to process, it exits. r.run() qpid-proton-0.14.0/examples/python/reactor/reactor-logger.py0000755000175000017500000000326112770711154023420 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor class Logger: def on_unhandled(self, name, event): print("LOG:", name, event) class Program: def on_reactor_init(self, event): print("Hello, World!") def on_reactor_final(self, event): print("Goodbye, World!") # You can pass multiple handlers to a reactor when you construct it. # Each of these handlers will see every event the reactor sees. By # combining this with on_unhandled, you can log each event that goes # to the reactor. r = Reactor(Program(), Logger()) r.run() # Note that if you wanted to add the logger later, you could also # write the above as below. All arguments to the reactor are just # added to the default handler for the reactor. def logging_enabled(): return False r = Reactor(Program()) if logging_enabled(): r.handler.add(Logger()) r.run() qpid-proton-0.14.0/examples/python/reactor/recv.py0000755000175000017500000000343012770711154021441 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import Message from proton.reactor import Reactor from proton.handlers import CHandshaker, CFlowController class Program: def __init__(self): self.handlers = [CHandshaker(), CFlowController()] self.message = Message() def on_reactor_init(self, event): # Create an amqp acceptor. event.reactor.acceptor("0.0.0.0", 5672) # There is an optional third argument to the Reactor.acceptor # call. Using it, we could supply a handler here that would # become the handler for all accepted connections. If we omit # it, the reactor simply inherets all the connection events. def on_delivery(self, event): # XXX: we could make rcv.recv(self.message) work here to # compliment the similar thing on send rcv = event.receiver if rcv and self.message.recv(rcv): print(self.message) event.delivery.settle() r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/scheduling.py0000755000175000017500000000357512770711154022641 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor class Program: def on_reactor_init(self, event): self.start = time.time() print("Hello, World!") # We can schedule a task event for some point in the future. # This will cause the reactor to stick around until it has a # chance to process the event. # The first argument is the delay. The second argument is the # handler for the event. We are just using self for now, but # we could pass in another object if we wanted. task = event.reactor.schedule(1.0, self) # We can ignore the task if we want to, but we can also use it # to pass stuff to the handler. task.something_to_say = "Yay" def on_timer_task(self, event): task = event.context # xxx: don't have a task property on event yet print(task.something_to_say, "my task is complete!") def on_reactor_final(self, event): print("Goodbye, World! (after %s long seconds)" % (time.time() - self.start)) r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/tornado-hello-world.py0000755000175000017500000000301512770711154024375 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import tornado.ioloop from tornado_app import TornadoApp # The proton reactor provides a general purpose event processing # library for writing reactive programs. A reactive program is defined # by a set of event handlers. An event handler is just any class or # object that defines the "on_" methods that it cares to # handle. class Program: # The reactor init event is produced by the reactor itself when it # starts. def on_reactor_init(self, event): print("Hello, World!") # The TornadoApp integrates a Reactor into tornado's ioloop. TornadoApp(Program()) # Now the tornado main loop will behave like the reactor's main loop. tornado.ioloop.IOLoop.instance().start() qpid-proton-0.14.0/examples/python/reactor/tornado_app.py0000644000175000017500000000550712770711154023014 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import tornado.ioloop from proton.reactor import Reactor from proton.handlers import IOHandler class TornadoApp: def __init__(self, *args): self.reactor = Reactor(*args) self.reactor.global_handler = self self.io = IOHandler() self.loop = tornado.ioloop.IOLoop.instance() self.count = 0 self.reactor.start() self.reactor.process() def on_reactor_quiesced(self, event): event.reactor.yield_() def on_unhandled(self, name, event): event.dispatch(self.io) def _events(self, sel): events = self.loop.ERROR if sel.reading: events |= self.loop.READ if sel.writing: events |= self.loop.WRITE return events def _schedule(self, sel): if sel.deadline: self.loop.add_timeout(sel.deadline, lambda: self.expired(sel)) def _expired(self, sel): sel.expired() def _process(self): self.reactor.process() if not self.reactor.quiesced: self.loop.add_callback(self._process) def _callback(self, sel, events): if self.loop.READ & events: sel.readable() if self.loop.WRITE & events: sel.writable() self._process() def on_selectable_init(self, event): sel = event.context if sel.fileno() >= 0: self.loop.add_handler(sel.fileno(), lambda fd, events: self._callback(sel, events), self._events(sel)) self._schedule(sel) self.count += 1 def on_selectable_updated(self, event): sel = event.context if sel.fileno() > 0: self.loop.update_handler(sel.fileno(), self._events(sel)) self._schedule(sel) def on_selectable_final(self, event): sel = event.context if sel.fileno() > 0: self.loop.remove_handler(sel.fileno()) sel.release() self.count -= 1 if self.count == 0: self.loop.add_callback(self._stop) def _stop(self): self.reactor.stop() self.loop.stop() qpid-proton-0.14.0/examples/python/reactor/unhandled.py0000755000175000017500000000236212770711154022447 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Reactor class Program: # If an event occurs and its handler doesn't have an on_ # method, the reactor will attempt to call the on_unhandled method # if it exists. This can be useful not only for debugging, but for # logging and for delegating/inheritance. def on_unhandled(self, name, event): print(name, event) r = Reactor(Program()) r.run() qpid-proton-0.14.0/examples/python/reactor/send.py0000755000175000017500000000636612770711154021446 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys from proton import Message, Url from proton.reactor import Reactor from proton.handlers import CHandshaker # This is a send in terms of low level AMQP events. There are handlers # that can streamline this significantly if you don't want to worry # about all the details, but it is useful to see how the AMQP engine # classes interact with handlers and events. class Send: def __init__(self, message, target): self.message = message self.target = target if target is not None else "examples" # Use the handlers property to add some default handshaking # behaviour. self.handlers = [CHandshaker()] def on_connection_init(self, event): conn = event.connection # Every session or link could have their own handler(s) if we # wanted simply by setting the "handler" slot on the # given session or link. ssn = conn.session() # If a link doesn't have an event handler, the events go to # its parent session. If the session doesn't have a handler # the events go to its parent connection. If the connection # doesn't have a handler, the events go to the reactor. snd = ssn.sender("sender") snd.target.address = self.target conn.open() ssn.open() snd.open() def on_transport_error(self, event): print event.transport.condition def on_link_flow(self, event): snd = event.sender if snd.credit > 0: dlv = snd.send(self.message) dlv.settle() snd.close() snd.session.close() snd.connection.close() class Program: def __init__(self, url, content): self.url = url self.content = content def on_reactor_init(self, event): # You can use the connection method to create AMQP connections. # This connection's handler is the Send object. All the events # for this connection will go to the Send object instead of # going to the reactor. If you were to omit the Send object, # all the events would go to the reactor. event.reactor.connection_to_host(self.url.host, self.url.port, Send(Message(self.content), self.url.path)) args = sys.argv[1:] url = Url(args.pop() if args else "localhost:5672/examples") content = args.pop() if args else "Hello World!" r = Reactor(Program(url, content)) r.run() qpid-proton-0.14.0/examples/python/reactor/tornado-send.py0000755000175000017500000000572612770711154023111 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys, tornado.ioloop from tornado_app import TornadoApp from proton import Message, Url from proton.handlers import CHandshaker class Send: def __init__(self, message, target): self.message = message self.target = target if target is not None else "examples" # Use the handlers property to add some default handshaking # behaviour. self.handlers = [CHandshaker()] def on_connection_init(self, event): conn = event.connection # Every session or link could have their own handler(s) if we # wanted simply by setting the "handler" slot on the # given session or link. ssn = conn.session() # If a link doesn't have an event handler, the events go to # its parent session. If the session doesn't have a handler # the events go to its parent connection. If the connection # doesn't have a handler, the events go to the reactor. snd = ssn.sender("sender") snd.target.address = self.target conn.open() ssn.open() snd.open() def on_link_flow(self, event): snd = event.sender if snd.credit > 0: dlv = snd.send(self.message) dlv.settle() snd.close() snd.session.close() snd.connection.close() class Program: def __init__(self, url, content): self.url = url self.content = content def on_reactor_init(self, event): # You can use the connection method to create AMQP connections. # This connection's handler is the Send object. All the events # for this connection will go to the Send object instead of # going to the reactor. If you were to omit the Send object, # all the events would go to the reactor. event.reactor.connection_to_host(self.url.host, self.url.port, Send(Message(self.content), self.url.path)) args = sys.argv[1:] url = Url(args.pop() if args else "localhost:5672/examples") content = args.pop() if args else "Hello World!" TornadoApp(Program(url, content)) tornado.ioloop.IOLoop.instance().start() qpid-proton-0.14.0/examples/python/recurring_timer.py0000755000175000017500000000251312770711154022244 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton.reactor import Container, Handler class Recurring(Handler): def __init__(self, period): self.period = period def on_reactor_init(self, event): self.container = event.reactor self.container.schedule(self.period, self) def on_timer_task(self, event): print("Tick...") self.container.schedule(self.period, self) try: container = Container(Recurring(1.0)) container.run() except KeyboardInterrupt: container.stop() print() qpid-proton-0.14.0/examples/python/recurring_timer_tornado.py0000755000175000017500000000262712770711154024000 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import time from proton.reactor import Handler from proton_tornado import TornadoLoop class Recurring(Handler): def __init__(self, period): self.period = period def on_start(self, event): self.container = event.container self.container.schedule(time.time() + self.period, subject=self) def on_timer(self, event): print("Tick...") self.container.schedule(time.time() + self.period, subject=self) try: container = TornadoLoop(Recurring(1.0)) container.run() except KeyboardInterrupt: container.stop() print() qpid-proton-0.14.0/examples/python/selected_recv.py0000755000175000017500000000251312770711154021653 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton.reactor import Container, Selector from proton.handlers import MessagingHandler class Recv(MessagingHandler): def __init__(self): super(Recv, self).__init__() def on_start(self, event): conn = event.container.connect("localhost:5672") event.container.create_receiver(conn, "examples", options=Selector("colour = 'green'")) def on_message(self, event): print(event.message.body) try: Container(Recv()).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/server_direct.py0000755000175000017500000000471412770711154021711 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import generate_uuid, Message from proton.handlers import MessagingHandler from proton.reactor import Container class Server(MessagingHandler): def __init__(self, url): super(Server, self).__init__() self.url = url self.senders = {} def on_start(self, event): print("Listening on", self.url) self.container = event.container self.acceptor = event.container.listen(self.url) def on_link_opening(self, event): if event.link.is_sender: if event.link.remote_source and event.link.remote_source.dynamic: event.link.source.address = str(generate_uuid()) self.senders[event.link.source.address] = event.link elif event.link.remote_target and event.link.remote_target.address: event.link.target.address = event.link.remote_target.address self.senders[event.link.remote_target.address] = event.link elif event.link.remote_source: event.link.source.address = event.link.remote_source.address elif event.link.remote_target: event.link.target.address = event.link.remote_target.address def on_message(self, event): print("Received", event.message) sender = self.senders.get(event.message.reply_to) if not sender: print("No link for reply") return sender.send(Message(address=event.message.reply_to, body=event.message.body.upper(), correlation_id=event.message.correlation_id)) try: Container(Server("0.0.0.0:8888")).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/server_tx.py0000755000175000017500000000567512770711154021101 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import Message from proton.reactor import Container from proton.handlers import MessagingHandler, TransactionHandler class TxRequest(TransactionHandler): def __init__(self, response, sender, request_delivery): super(TxRequest, self).__init__() self.response = response self.sender = sender self.request_delivery = request_delivery def on_transaction_declared(self, event): event.transaction.send(self.sender, self.response) event.transaction.accept(self.request_delivery) event.transaction.commit() def on_transaction_committed(self, event): print("Request processed successfully") def on_transaction_aborted(self, event): print("Request processing aborted") class TxServer(MessagingHandler): def __init__(self, host, address): super(TxServer, self).__init__(auto_accept=False) self.host = host self.address = address def on_start(self, event): self.container = event.container self.conn = event.container.connect(self.host, reconnect=False) self.receiver = event.container.create_receiver(self.conn, self.address) self.senders = {} self.relay = None def on_message(self, event): sender = self.relay if not sender: sender = self.senders.get(event.message.reply_to) if not sender: sender = self.container.create_sender(self.conn, event.message.reply_to) self.senders[event.message.reply_to] = sender response = Message(address=event.message.reply_to, body=event.message.body.upper(), correlation_id=event.message.correlation_id) self.container.declare_transaction(self.conn, handler=TxRequest(response, sender, event.delivery)) def on_connection_open(self, event): if event.connection.remote_offered_capabilities and 'ANONYMOUS-RELAY' in event.connection.remote_offered_capabilities: self.relay = self.container.create_sender(self.conn, None) try: Container(TxServer("localhost:5672", "examples")).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/simple_recv.py0000755000175000017500000000414012770711154021352 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import optparse from proton.handlers import MessagingHandler from proton.reactor import Container class Recv(MessagingHandler): def __init__(self, url, count): super(Recv, self).__init__() self.url = url self.expected = count self.received = 0 def on_start(self, event): event.container.create_receiver(self.url) def on_message(self, event): if event.message.id and event.message.id < self.received: # ignore duplicate message return if self.expected == 0 or self.received < self.expected: print(event.message.body) self.received += 1 if self.received == self.expected: event.receiver.close() event.connection.close() parser = optparse.OptionParser(usage="usage: %prog [options]") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address from which messages are received (default %default)") parser.add_option("-m", "--messages", type="int", default=100, help="number of messages to receive; 0 receives indefinitely (default %default)") opts, args = parser.parse_args() try: Container(Recv(opts.address, opts.messages)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/sync_client.py0000755000175000017500000000420312770711154021354 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # """ Demonstrates the client side of the synchronous request-response pattern (also known as RPC or Remote Procecure Call) using proton. """ from __future__ import print_function import optparse from proton import Message, Url, ConnectionException, Timeout from proton.utils import SyncRequestResponse, BlockingConnection from proton.handlers import IncomingMessageHandler import sys parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send requests to the supplied address and print responses.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") parser.add_option("-t", "--timeout", type="float", default=5, help="Give up after this time out (default %default)") opts, args = parser.parse_args() url = Url(opts.address) client = SyncRequestResponse(BlockingConnection(url, timeout=opts.timeout), url.path) try: REQUESTS= ["Twas brillig, and the slithy toves", "Did gire and gymble in the wabe.", "All mimsy were the borogroves,", "And the mome raths outgrabe."] for request in REQUESTS: response = client.call(Message(body=request)) print("%s => %s" % (request, response.body)) finally: client.connection.close() qpid-proton-0.14.0/examples/python/tx_recv.py0000755000175000017500000000603012770711154020514 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import optparse from proton import Url from proton.reactor import Container from proton.handlers import MessagingHandler, TransactionHandler class TxRecv(MessagingHandler, TransactionHandler): def __init__(self, url, messages, batch_size): super(TxRecv, self).__init__(prefetch=0, auto_accept=False) self.url = Url(url) self.expected = messages self.batch_size = batch_size self.current_batch = 0 self.committed = 0 def on_start(self, event): self.container = event.container self.conn = self.container.connect(self.url) self.receiver = self.container.create_receiver(self.conn, self.url.path) self.container.declare_transaction(self.conn, handler=self) self.transaction = None def on_message(self, event): print(event.message.body) self.transaction.accept(event.delivery) self.current_batch += 1 if self.current_batch == self.batch_size: self.transaction.commit() self.transaction = None def on_transaction_declared(self, event): self.receiver.flow(self.batch_size) self.transaction = event.transaction def on_transaction_committed(self, event): self.committed += self.current_batch self.current_batch = 0 if self.expected == 0 or self.committed < self.expected: self.container.declare_transaction(self.conn, handler=self) else: event.connection.close() def on_disconnected(self, event): self.current_batch = 0 parser = optparse.OptionParser(usage="usage: %prog [options]") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address from which messages are received (default %default)") parser.add_option("-m", "--messages", type="int", default=100, help="number of messages to receive; 0 receives indefinitely (default %default)") parser.add_option("-b", "--batch-size", type="int", default=10, help="number of messages in each transaction (default %default)") opts, args = parser.parse_args() try: Container(TxRecv(opts.address, opts.messages, opts.batch_size)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/proton_tornado.py0000755000175000017500000000701012770711154022110 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import tornado.ioloop from proton.reactor import Container as BaseContainer from proton.handlers import IOHandler class TornadoLoopHandler: def __init__(self, loop=None, handler_base=None): self.loop = loop or tornado.ioloop.IOLoop.instance() self.io = handler_base or IOHandler() self.count = 0 def on_reactor_init(self, event): self.reactor = event.reactor def on_reactor_quiesced(self, event): event.reactor.yield_() def on_unhandled(self, name, event): event.dispatch(self.io) def _events(self, sel): events = self.loop.ERROR if sel.reading: events |= self.loop.READ if sel.writing: events |= self.loop.WRITE return events def _schedule(self, sel): if sel.deadline: self.loop.add_timeout(sel.deadline, lambda: self.expired(sel)) def _expired(self, sel): sel.expired() def _process(self): self.reactor.process() if not self.reactor.quiesced: self.loop.add_callback(self._process) def _callback(self, sel, events): if self.loop.READ & events: sel.readable() if self.loop.WRITE & events: sel.writable() self._process() def on_selectable_init(self, event): sel = event.context if sel.fileno() >= 0: self.loop.add_handler(sel.fileno(), lambda fd, events: self._callback(sel, events), self._events(sel)) self._schedule(sel) self.count += 1 def on_selectable_updated(self, event): sel = event.context if sel.fileno() > 0: self.loop.update_handler(sel.fileno(), self._events(sel)) self._schedule(sel) def on_selectable_final(self, event): sel = event.context if sel.fileno() > 0: self.loop.remove_handler(sel.fileno()) sel.release() self.count -= 1 if self.count == 0: self.loop.add_callback(self._stop) def _stop(self): self.reactor.stop() self.loop.stop() class Container(object): def __init__(self, *handlers, **kwargs): self.tornado_loop = kwargs.get('loop', tornado.ioloop.IOLoop.instance()) kwargs['global_handler'] = TornadoLoopHandler(self.tornado_loop, kwargs.get('handler_base', None)) self.container = BaseContainer(*handlers, **kwargs) def initialise(self): self.container.start() self.container.process() def run(self): self.initialise() self.tornado_loop.start() def touch(self): self._process() def _process(self): self.container.process() if not self.container.quiesced: self.tornado_loop.add_callback(self._process) qpid-proton-0.14.0/examples/python/README0000644000175000017500000001512412770711154017351 0ustar danieldanielMost (though not all) of the current examples require a broker or similar intermediary that supports the AMQP 1.0 protocol, allows anonymous connections and accepts links to and from a node named 'examples'. A very simple broker emulating script - broker.py - is provided against which the examples can also be run (transactions are not yet supported in this script). Note: For builds that include SASL support via the cyrus sasl library, those examples that accept incoming connections may require some SASL configuration which is described below. ------------------------------------------------------------------ helloworld.py Basic example that connects to an intermediary on localhost:5672, establishes a subscription from the 'examples' node on that intermediary, then creates a sending link to the same node and sends one message. On receving the message back via the subcription, the connection is closed. helloworld_blocking.py The same as the basic helloworld.py, but using a synchronous/sequential style wrapper on top of the asynchronous/reactive API. The purpose of this example is just to show how different functionality can be easily layered should it be desired. helloworld_direct.py A variant of the basic helloworld example, that does not use an intermediary, but listens for incoming connections itself. It establishes a connection to itself with a link over which a single message is sent. This demonstrates the ease with which a simple daemon can be built using the API. helloworld_tornado.py helloworld_direct_tornado.py These are variant of the helloworld.py and helloworld_direct.py examples that use the event loop from the tornado library, rather than that provided within proton itself and demonstrate how proton can be used with external loops. ------------------------------------------------------------------- simple_send.py An example of sending a fixed number of messages and tracking their (asynchronous) acknowledgement. Handles disconnection while maintaining an at-least-once guarantee (there may be duplicates, but no message in the sequence should be lost). Messages are sent through the 'examples' node on an intermediary accessible on port 5672 on localhost. simple_recv.py Subscribes to the 'examples' node on an intermediary accessible on port 5672 on localhost. Simply prints out the body of received messages. db_send.py A more realistic sending example, where the messages come from records in a simple database table. On being acknowledged the records can be deleted from the table. The database access is done in a separate thread, so as not to block the event thread during data access. Messages are sent through the 'examples' node on an intermediary accessible on port 5672 on localhost. db_recv.py A receiving example that records messages received from the 'examples' node on localhost:5672 in a database table and only acknowledges them when the insert completes. Database access is again done in a separate thread from the event loop. db_ctrl.py A utility for setting up the database tables for the two examples above. Takes two arguments, the action to perform and the name of the database on which to perfom it. The database used by db_send.py is src_db, that by db_recv.py is dst_db. The valid actions are 'init', which creates the table, 'list' which displays the contents and 'insert' which inserts records from standard-in and is used to populate src_db, e.g. for i in `seq 1 50`; do echo "Message-$i"; done | ./db_ctrl.py insert src_db. tx_send.py A sender that sends messages in atomic batches using local transactions (this example does not persist the messages in any way). tx_recv.py A receiver example that accepts batches of messages using local transactions. tx_recv_interactive.py A testing utility that allow interactive control of the transactions. Actions are keyed in to the console, 'fetch' will request another message, 'abort' will abort the transaction, 'commit' will commit it. The various send/recv examples can be mixed and matched if desired. direct_send.py An example that accepts incoming links and connections over which it will then send out messages. Can be used with simple_recv.py or db_recv.py for direct, non-intermediated communication. direct_recv.py An example that accepts incoming links and connections over which it will then receive messages, printing out the content. Can be used with simple_send.py or db_send.py for direct, non-intermediated communication. ------------------------------------------------------------------- client.py The client part of a request-response example. Sends requests and prints out responses. Requires an intermediary that supports the AMQP 1.0 dynamic nodes on which the responses are received. The requests are sent through the 'examples' node. server.py The server part of a request-response example, that receives requests via the examples node, converts the body to uppercase and sends the result back to the indicated reply address. sync_client.py A variant of the client part, that uses a blocking/synchronous style instead of the reactive/asynchronous style. client_http.py A variant of the client part that takes the input to be submitted in the request over HTTP (point your browser to localhost:8888/client) server_tx.py A variant of the server part that consumes the request and sends out the response atomically in a local transaction. direct_server.py A variant of the server part of a request-response example, that accepts incoming connections and does not need an intermediary. Much like the original server, it receives incoming requests, converts the body to uppercase and sends the result back to the indicated reply address. Can be used in conjunction with any of the client alternatives. ------------------------------------------------------------------- selected_recv.py An example that uses a selector filter. ------------------------------------------------------------------- recurring_timer.py An example showing a simple timer event. recurring_timer_tornado.py A variant of the above that uses the tornado eventloop instead. ------------------------------------------------------------------- SASL configuration If your build includes extra SASL support (provided via the cyrus SASL library), you may need to provide some configuration to enable examples that accept incoming connections (i.e. those with 'direct' in the name). This is done by supplying a config file name proton-server.conf. The directory in which it is in can be specified via the PN_SASL_CONFIG_PATH environment variable. A simple example config file is included along with these examples, enabling only the EXTERNAL and ANONYMOUS mechanisms by default.qpid-proton-0.14.0/examples/python/client.py0000755000175000017500000000471412770711154020327 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals import optparse from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container, DynamicNodeProperties class Client(MessagingHandler): def __init__(self, url, requests): super(Client, self).__init__() self.url = url self.requests = requests def on_start(self, event): self.sender = event.container.create_sender(self.url) self.receiver = event.container.create_receiver(self.sender.connection, None, dynamic=True) def next_request(self): if self.receiver.remote_source.address: req = Message(reply_to=self.receiver.remote_source.address, body=self.requests[0]) self.sender.send(req) def on_link_opened(self, event): if event.receiver == self.receiver: self.next_request() def on_message(self, event): print("%s => %s" % (self.requests.pop(0), event.message.body)) if self.requests: self.next_request() else: event.connection.close() REQUESTS= ["Twas brillig, and the slithy toves", "Did gire and gymble in the wabe.", "All mimsy were the borogroves,", "And the mome raths outgrabe."] parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send requests to the supplied address and print responses.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") opts, args = parser.parse_args() Container(Client(opts.address, args or REQUESTS)).run() qpid-proton-0.14.0/examples/python/db_send.py0000755000175000017500000000743512770711154020452 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals import optparse import time try: import Queue except: import queue as Queue from proton import Message from proton.handlers import MessagingHandler from proton.reactor import ApplicationEvent, Container, EventInjector from db_common import Db class Send(MessagingHandler): def __init__(self, url, count): super(Send, self).__init__() self.url = url self.delay = 0 self.sent = 0 self.confirmed = 0 self.load_count = 0 self.records = Queue.Queue(maxsize=50) self.target = count self.db = Db("src_db", EventInjector()) def keep_sending(self): return self.target == 0 or self.sent < self.target def on_start(self, event): self.container = event.container self.container.selectable(self.db.injector) self.sender = self.container.create_sender(self.url) def on_records_loaded(self, event): if self.records.empty(): if event.subject == self.load_count: print("Exhausted available data, waiting to recheck...") # check for new data after 5 seconds self.container.schedule(5, self) else: self.send() def request_records(self): if not self.records.full(): print("loading records...") self.load_count += 1 self.db.load(self.records, event=ApplicationEvent("records_loaded", link=self.sender, subject=self.load_count)) def on_sendable(self, event): self.send() def send(self): while self.sender.credit and not self.records.empty(): if not self.keep_sending(): return record = self.records.get(False) id = record['id'] self.sender.send(Message(id=id, durable=True, body=record['description']), tag=str(id)) self.sent += 1 print("sent message %s" % id) self.request_records() def on_settled(self, event): id = int(event.delivery.tag) self.db.delete(id) print("settled message %s" % id) self.confirmed += 1 if self.confirmed == self.target: event.connection.close() self.db.close() def on_disconnected(self, event): self.db.reset() self.sent = self.confirmed def on_timer_task(self, event): print("Rechecking for data...") self.request_records() parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send messages to the supplied address.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") parser.add_option("-m", "--messages", type="int", default=0, help="number of messages to send; 0 sends indefinitely (default %default)") opts, args = parser.parse_args() try: Container(Send(opts.address, opts.messages)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/direct_send.py0000755000175000017500000000451512770711154021333 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals import optparse from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container class Send(MessagingHandler): def __init__(self, url, messages): super(Send, self).__init__() self.url = url self.sent = 0 self.confirmed = 0 self.total = messages def on_start(self, event): self.acceptor = event.container.listen(self.url) def on_sendable(self, event): while event.sender.credit and self.sent < self.total: msg = Message(id=(self.sent+1), body={'sequence':(self.sent+1)}) event.sender.send(msg) self.sent += 1 def on_accepted(self, event): self.confirmed += 1 if self.confirmed == self.total: print("all messages confirmed") event.connection.close() self.acceptor.close() def on_disconnected(self, event): self.sent = self.confirmed parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send messages to the supplied address.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") parser.add_option("-m", "--messages", type="int", default=100, help="number of messages to send (default %default)") opts, args = parser.parse_args() try: Container(Send(opts.address, opts.messages)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/helloworld.py0000755000175000017500000000315012770711154021215 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container class HelloWorld(MessagingHandler): def __init__(self, server, address): super(HelloWorld, self).__init__() self.server = server self.address = address def on_start(self, event): conn = event.container.connect(self.server) event.container.create_receiver(conn, self.address) event.container.create_sender(conn, self.address) def on_sendable(self, event): event.sender.send(Message(body="Hello World!")) event.sender.close() def on_message(self, event): print(event.message.body) event.connection.close() Container(HelloWorld("localhost:5672", "examples")).run() qpid-proton-0.14.0/examples/python/helloworld_direct.py0000755000175000017500000000314012770711154022546 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container class HelloWorld(MessagingHandler): def __init__(self, url): super(HelloWorld, self).__init__() self.url = url def on_start(self, event): self.acceptor = event.container.listen(self.url) event.container.create_sender(self.url) def on_sendable(self, event): event.sender.send(Message(body="Hello World!")) event.sender.close() def on_message(self, event): print(event.message.body) def on_accepted(self, event): event.connection.close() def on_connection_closed(self, event): self.acceptor.close() Container(HelloWorld("localhost:8888/examples")).run() qpid-proton-0.14.0/examples/python/proton-server.conf0000644000175000017500000000003612770711154022161 0ustar danieldanielmech_list: EXTERNAL ANONYMOUS qpid-proton-0.14.0/examples/python/proton_server.py0000755000175000017500000000337612770711154021763 0ustar danieldanielfrom __future__ import print_function # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 proton import Message from proton.reactor import Container from proton.handlers import MessagingHandler class Server(MessagingHandler): def __init__(self, host, address): super(Server, self).__init__() self.container = Container(self) self.conn = self.container.connect(host) self.receiver = self.container.create_receiver(self.conn, address) self.sender = self.container.create_sender(self.conn, None) def on_message(self, event): self.on_request(event.message.body, event.message.reply_to) def on_connection_close(self, endpoint, error): if error: print("Closed due to %s" % error) self.conn.close() def run(self): self.container.run() def send(self, response, reply_to): msg = Message(body=response) if self.sender: msg.address = reply_to self.sender.send(msg) def on_request(self, request, reply_to): pass qpid-proton-0.14.0/examples/python/server.py0000755000175000017500000000336612770711154020361 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container class Server(MessagingHandler): def __init__(self, url, address): super(Server, self).__init__() self.url = url self.address = address def on_start(self, event): print("Listening on", self.url) self.container = event.container self.conn = event.container.connect(self.url) self.receiver = event.container.create_receiver(self.conn, self.address) self.server = self.container.create_sender(self.conn, None) def on_message(self, event): print("Received", event.message) self.server.send(Message(address=event.message.reply_to, body=event.message.body.upper(), correlation_id=event.message.correlation_id)) try: Container(Server("0.0.0.0:5672", "examples")).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/simple_send.py0000755000175000017500000000444212770711154021351 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals import optparse from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container class Send(MessagingHandler): def __init__(self, url, messages): super(Send, self).__init__() self.url = url self.sent = 0 self.confirmed = 0 self.total = messages def on_start(self, event): event.container.create_sender(self.url) def on_sendable(self, event): while event.sender.credit and self.sent < self.total: msg = Message(id=(self.sent+1), body={'sequence':(self.sent+1)}) event.sender.send(msg) self.sent += 1 def on_accepted(self, event): self.confirmed += 1 if self.confirmed == self.total: print("all messages confirmed") event.connection.close() def on_disconnected(self, event): self.sent = self.confirmed parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send messages to the supplied address.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") parser.add_option("-m", "--messages", type="int", default=100, help="number of messages to send (default %default)") opts, args = parser.parse_args() try: Container(Send(opts.address, opts.messages)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/test_examples.py0000644000175000017500000001515212770711154021721 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import sys import subprocess import time import unittest if sys.version_info[0] == 2: _unicode_prefix = 'u' else: _unicode_prefix = '' class ExamplesTest(unittest.TestCase): def test_helloworld(self, example="helloworld.py"): p = subprocess.Popen([example], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) p.wait() output = [l.strip() for l in p.stdout] self.assertEqual(output, ['Hello World!']) def test_helloworld_direct(self): self.test_helloworld('helloworld_direct.py') def test_helloworld_blocking(self): self.test_helloworld('helloworld_blocking.py') def test_helloworld_tornado(self): self.test_helloworld('helloworld_tornado.py') def test_helloworld_direct_tornado(self): self.test_helloworld('helloworld_direct_tornado.py') def test_simple_send_recv(self, recv='simple_recv.py', send='simple_send.py'): r = subprocess.Popen([recv], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) s = subprocess.Popen([send], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) s.wait() r.wait() actual = [l.strip() for l in r.stdout] expected = ["{%s'sequence': int32(%i)}" % (_unicode_prefix, (i+1)) for i in range(100)] self.assertEqual(actual, expected) def test_client_server(self, client=['client.py'], server=['server.py'], sleep=0): s = subprocess.Popen(server, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) if sleep: time.sleep(sleep) c = subprocess.Popen(client, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) c.wait() s.terminate() actual = [l.strip() for l in c.stdout] inputs = ["Twas brillig, and the slithy toves", "Did gire and gymble in the wabe.", "All mimsy were the borogroves,", "And the mome raths outgrabe."] expected = ["%s => %s" % (l, l.upper()) for l in inputs] self.assertEqual(actual, expected) def test_sync_client_server(self): self.test_client_server(client=['sync_client.py']) def test_client_server_tx(self): self.test_client_server(server=['server_tx.py']) def test_sync_client_server_tx(self): self.test_client_server(client=['sync_client.py'], server=['server_tx.py']) def test_client_server_direct(self): self.test_client_server(client=['client.py', '-a', 'localhost:8888/examples'], server=['server_direct.py'], sleep=0.5) def test_sync_client_server_direct(self): self.test_client_server(client=['sync_client.py', '-a', 'localhost:8888/examples'], server=['server_direct.py'], sleep=0.5) def test_db_send_recv(self): self.maxDiff = None # setup databases subprocess.check_call(['db_ctrl.py', 'init', './src_db']) subprocess.check_call(['db_ctrl.py', 'init', './dst_db']) fill = subprocess.Popen(['db_ctrl.py', 'insert', './src_db'], stdin=subprocess.PIPE, stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) for i in range(100): fill.stdin.write("Message-%i\n" % (i+1)) fill.stdin.close() fill.wait() # run send and recv r = subprocess.Popen(['db_recv.py', '-m', '100'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) s = subprocess.Popen(['db_send.py', '-m', '100'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) s.wait() r.wait() # verify output of receive actual = [l.strip() for l in r.stdout] expected = ["inserted message %i" % (i+1) for i in range(100)] self.assertEqual(actual, expected) # verify state of databases v = subprocess.Popen(['db_ctrl.py', 'list', './dst_db'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) v.wait() expected = ["(%i, %s'Message-%i')" % ((i+1), _unicode_prefix, (i+1)) for i in range(100)] actual = [l.strip() for l in v.stdout] self.assertEqual(actual, expected) def test_tx_send_tx_recv(self): self.test_simple_send_recv(recv='tx_recv.py', send='tx_send.py') def test_simple_send_direct_recv(self): self.maxDiff = None r = subprocess.Popen(['direct_recv.py', '-a', 'localhost:8888'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) time.sleep(0.5) s = subprocess.Popen(['simple_send.py', '-a', 'localhost:8888'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) s.wait() r.wait() actual = [l.strip() for l in r.stdout] expected = ["{%s'sequence': int32(%i)}" % (_unicode_prefix, (i+1)) for i in range(100)] self.assertEqual(actual, expected) def test_direct_send_simple_recv(self): s = subprocess.Popen(['direct_send.py', '-a', 'localhost:8888'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) time.sleep(0.5) r = subprocess.Popen(['simple_recv.py', '-a', 'localhost:8888'], stderr=subprocess.STDOUT, stdout=subprocess.PIPE, universal_newlines=True) r.wait() s.wait() actual = [l.strip() for l in r.stdout] expected = ["{%s'sequence': int32(%i)}" % (_unicode_prefix, (i+1)) for i in range(100)] self.assertEqual(actual, expected) qpid-proton-0.14.0/examples/python/tx_recv_interactive.py0000755000175000017500000000535412770711154023121 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys import threading from proton.reactor import ApplicationEvent, Container, EventInjector from proton.handlers import MessagingHandler, TransactionHandler class TxRecv(MessagingHandler, TransactionHandler): def __init__(self): super(TxRecv, self).__init__(prefetch=0, auto_accept=False) def on_start(self, event): self.container = event.container self.conn = self.container.connect("localhost:5672") self.receiver = self.container.create_receiver(self.conn, "examples") self.container.declare_transaction(self.conn, handler=self, settle_before_discharge=True) self.transaction = None def on_message(self, event): print(event.message.body) self.transaction.accept(event.delivery) def on_transaction_declared(self, event): self.transaction = event.transaction print("transaction declared") def on_transaction_committed(self, event): print("transaction committed") self.container.declare_transaction(self.conn, handler=self) def on_transaction_aborted(self, event): print("transaction aborted") self.container.declare_transaction(self.conn, handler=self) def on_commit(self, event): self.transaction.commit() def on_abort(self, event): self.transaction.abort() def on_fetch(self, event): self.receiver.flow(1) def on_quit(self, event): c = self.receiver.connection self.receiver.close() c.close() try: reactor = Container(TxRecv()) events = EventInjector() reactor.selectable(events) thread = threading.Thread(target=reactor.run) thread.daemon=True thread.start() print("Enter 'fetch', 'commit' or 'abort'") while True: line = sys.stdin.readline() if line: events.trigger(ApplicationEvent(line.strip())) else: break except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/python/tx_send.py0000755000175000017500000000672212770711154020516 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function, unicode_literals import optparse from proton import Message, Url from proton.reactor import Container from proton.handlers import MessagingHandler, TransactionHandler class TxSend(MessagingHandler, TransactionHandler): def __init__(self, url, messages, batch_size): super(TxSend, self).__init__() self.url = Url(url) self.current_batch = 0 self.committed = 0 self.confirmed = 0 self.total = messages self.batch_size = batch_size def on_start(self, event): self.container = event.container self.conn = self.container.connect(self.url) self.sender = self.container.create_sender(self.conn, self.url.path) self.container.declare_transaction(self.conn, handler=self) self.transaction = None def on_transaction_declared(self, event): self.transaction = event.transaction self.send() def on_sendable(self, event): self.send() def send(self): while self.transaction and self.sender.credit and (self.committed + self.current_batch) < self.total: seq = self.committed + self.current_batch + 1 msg = Message(id=seq, body={'sequence':seq}) self.transaction.send(self.sender, msg) self.current_batch += 1 if self.current_batch == self.batch_size: self.transaction.commit() self.transaction = None def on_accepted(self, event): if event.sender == self.sender: self.confirmed += 1 def on_transaction_committed(self, event): self.committed += self.current_batch if self.committed == self.total: print("all messages committed") event.connection.close() else: self.current_batch = 0 self.container.declare_transaction(self.conn, handler=self) def on_disconnected(self, event): self.current_batch = 0 parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send messages transactionally to the supplied address.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") parser.add_option("-m", "--messages", type="int", default=100, help="number of messages to send (default %default)") parser.add_option("-b", "--batch-size", type="int", default=10, help="number of messages in each transaction (default %default)") opts, args = parser.parse_args() try: Container(TxSend(opts.address, opts.messages, opts.batch_size)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/examples/ruby/0000755000175000017500000000000012770711154016126 5ustar danieldanielqpid-proton-0.14.0/examples/ruby/engine_recv.rb0000644000175000017500000001027412770711154020743 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require "qpid_examples" require "optparse" DEFAULT_PORT = 5672 options = { :port => DEFAULT_PORT, :debug => false, :verbose => false, } OptionParser.new do |opts| opts.banner = "Usage: engine_recv.rb [options]" opts.on("-p [port]", "--port [port]", "The port to use (def. #{DEFAULT_PORT})") do |port| options[:port] = port end opts.on("-v", "--verbose", "Enable verbose output") do options[:verbose] = true end opts.on("-d", "--debug", "Enable debugging") do options[:debug] = true end opts.parse! end server = TCPServer.new('localhost', options[:port]) last_time = Time.now message_count = 0 driver = Driver.new collector = Qpid::Proton::Event::Collector.new loop do begin client = server.accept_nonblock rescue Errno::EAGAIN, Errno::ECONNABORTED, Errno::EINTR, Errno::EWOULDBLOCK => error end unless client.nil? puts "Connection from #{client.peeraddr.last}" connection = Qpid::Proton::Connection.new connection.collect(collector) transport = Qpid::Proton::Transport.new(Qpid::Proton::Transport::SERVER) transport.bind(connection) selectable = Selectable.new(transport, client) driver.add(selectable) end # let the driver process data driver.process event = collector.peek while !event.nil? puts "EVENT: #{event}" if options[:debug] case event.type when Qpid::Proton::Event::CONNECTION_INIT conn = event.connection if conn.state & Qpid::Proton::Endpoint::REMOTE_UNINIT conn.transport.sasl.done(Qpid::Proton::SASL::OK) end when Qpid::Proton::Event::CONNECTION_BOUND conn = event.connection if conn.state & Qpid::Proton::Endpoint::LOCAL_UNINIT conn.open end when Qpid::Proton::Event::CONNECTION_REMOTE_CLOSE conn = event.context if !(conn.state & Qpid::Proton::Endpoint::LOCAL_CLOSED) conn.close end when Qpid::Proton::Event::SESSION_REMOTE_OPEN session = event.session if session.state & Qpid::Proton::Endpoint::LOCAL_UNINIT session.incoming_capacity = 1000000 session.open end when Qpid::Proton::Event::SESSION_REMOTE_CLOSE session = event.session if !(session.state & Qpid::Proton::Endpoint::LOCAL_CLOSED) session.close end when Qpid::Proton::Event::LINK_REMOTE_OPEN link = event.link if link.state & Qpid::Proton::Endpoint::LOCAL_UNINIT link.open link.flow 400 end when Qpid::Proton::Event::LINK_REMOTE_CLOSE link = event.context if !(link.state & Qpid::Proton::Endpoint::LOCAL_CLOSED) link.close end when Qpid::Proton::Event::DELIVERY link = event.link delivery = event.delivery if delivery.readable? && !delivery.partial? # decode the message and display it msg = Qpid::Proton::Util::Engine.receive_message(delivery) message_count += 1 puts "Received:" puts " Count=#{message_count}" if options[:verbose] puts " From=#{msg.id}" if msg.id puts " Reply to=#{msg.reply_to}" if msg.reply_to puts " Subject=#{msg.subject}" if msg.subject puts " Body=#{msg.body}" if msg.body puts "" delivery.settle credit = link.credit link.flow(200) if credit <= 200 end when Qpid::Proton::Event::TRANSPORT driver.process end collector.pop event = collector.peek end end qpid-proton-0.14.0/examples/ruby/engine_send.rb0000644000175000017500000000647712770711154020747 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_examples' require "optparse" DEFAULT_ADDRESS = "0.0.0.0:5672" options = { :address => DEFAULT_ADDRESS, :debug => false, :verbose => false, :count => 1, :content => "This message was sent #{Time.new}" } OptionParser.new do |opts| opts.banner = "Usage: engine_recv.rb [options]" opts.on("-a [address]", "--address [address]", "The target address (def. #{DEFAULT_ADDRESS})") do |address| options[:address] = address end opts.on("-C [content]", "--content [content]", "The message content") do |content| options[:content] = content end opts.on("-c [count]", "--count [count]", "The number of messages to send (def. 1)") do |count| options[:count] = count.to_i end opts.on("-v", "--verbose", "Enable verbose output") do options[:verbose] = true end opts.on("-d", "--debug", "Enable debugging") do options[:debug] = true end opts.parse! end driver = Driver.new conn = Qpid::Proton::Connection.new collector = Qpid::Proton::Event::Collector.new conn.collect(collector) session = conn.session conn.open session.open sender = session.sender("tvc_15_1") sender.target.address = "queue" sender.open transport = Qpid::Proton::Transport.new transport.bind(conn) address, port = options[:address].split(":") socket = TCPSocket.new(address, port) selectable = Selectable.new(transport, socket) sent_count = 0 sent_count = 0 driver.add(selectable) loop do # let the driver process driver.process event = collector.peek unless event.nil? print "EVENT: #{event}\n" if options[:debug] case event.type when Qpid::Proton::Event::LINK_FLOW sender = event.sender credit = sender.credit message = Qpid::Proton::Message.new if credit > 0 && sent_count < options[:count] sent_count = sent_count.next message.clear message.address = options[:address] message.subject = "Message #{sent_count}..." message.body = options[:content] delivery = sender.delivery("#{sent_count}") sender.send(message.encode) delivery.settle sender.advance credit = sender.credit else sender.close end when Qpid::Proton::Event::LINK_LOCAL_CLOSE link = event.link link.close link.session.close when Qpid::Proton::Event::SESSION_LOCAL_CLOSE session = event.session session.connection.close when Qpid::Proton::Event::CONNECTION_LOCAL_CLOSE break end collector.pop event = collector.peek end end qpid-proton-0.14.0/examples/ruby/lib/0000755000175000017500000000000012770711154016674 5ustar danieldanielqpid-proton-0.14.0/examples/ruby/lib/debugging.rb0000644000175000017500000000157412770711154021163 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ module Debugging def debug(text) print "[#{Time.now.strftime('%s')}] #{text}\n" end end qpid-proton-0.14.0/examples/ruby/lib/driver.rb0000644000175000017500000000344312770711154020520 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ class Driver def initialize @selectables = {} end def add(selectable) @selectables[selectable.fileno] = selectable end def process reading = [] writing = [] @selectables.each_value do |sel| if sel.closed? || sel.fileno.nil? @selectables.delete(sel.fileno) else begin reading << sel.to_io if sel.reading? writing << sel.to_io if sel.writing? rescue Exception => error puts "Error: #{error}" puts error.backtrace.join("\n"); # @selectables.delete(sel.fileno) end end end read_from, write_to = IO.select(reading, writing, [], 0) unless read_from.nil? read_from.each do |r| sel = @selectables[r.fileno] sel.readable unless sel.nil? || sel.closed? end end begin unless write_to.nil? write_to.each do |w| sel = @selectables[w.fileno] sel.writable unless sel.nil? || sel.closed? end end end end end qpid-proton-0.14.0/examples/ruby/lib/qpid_examples.rb0000644000175000017500000000162612770711154022061 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require "qpid_proton" require "selectable" require "driver" require "socket" require "monitor" include Socket::Constants qpid-proton-0.14.0/examples/ruby/lib/selectable.rb0000644000175000017500000000505712770711154021333 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ class Selectable attr_reader :transport def initialize(transport, socket) @transport = transport @socket = socket @socket.autoclose = true @write_done = false @read_done = false end def closed? return true if @socket.closed? return false if !@read_done && !@write_done @socket.close true end def fileno @socket.fileno unless @socket.closed? end def to_io @socket end def reading? return false if @read_done c = @transport.capacity if c > 0 return true elsif c < 0 @read_done = true return false else return false end end def writing? return false if @write_done begin p = @transport.pending if p > 0 return true elsif p < 0 @write_done = true return false else return false end rescue Qpid::Proton::TransportError => error @write_done = true return false end end def readable c = @transport.capacity if c > 0 begin data = @socket.recv(c) if data @transport.push(data) else @transport.close_tail end rescue Exception => error puts "read error; #{error}" @transport.close_tail @read_done = true end elsif c < 0 @read_done = true end end def writable begin p = @transport.pending if p > 0 data = @transport.peek(p) n = @socket.send(data, 0) @transport.pop(n) elsif p < 0 @write_done = true end rescue Exception => error puts "write error: #{error}" puts error.backtrace.join("\n") @transport.close_head @write_done = true end end def tick(now) @transport.tick(now) end end qpid-proton-0.14.0/examples/ruby/lib/send_and_receive.rb0000644000175000017500000000426612770711154022506 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ class ExampleSend < Qpid::Proton::Handler::MessagingHandler attr_reader :url def initialize(url, expected) super() @url = url @sent = 0 @confirmed = 0 @expected = expected end def on_sendable(event) while event.sender.credit > 0 && @sent < @expected msg = Qpid::Proton::Message.new msg.body = "sequence #{@sent}" msg.id = @sent event.sender.send(msg) @sent = @sent + 1 end end def on_accepted(event) @confirmed = @confirmed + 1 if self.finished? puts "#{@expected > 1 ? 'All ' : ''}#{@expected} message#{@expected > 1 ? 's' : ''} confirmed!" event.connection.close end end def on_disconnected(event) @sent = @confirmed end def finished? @confirmed == @expected end end class ExampleReceive < Qpid::Proton::Handler::MessagingHandler attr_reader :url def initialize(url, expected) super() @url = url @expected = expected @received = 0 end def on_message(event) if event.message.id.nil? || event.message.id < @received puts "Missing or old message id: id=#{event.message.id}" return end if @expected.zero? || (@received < @expected) puts "Received: #{event.message.body}" @received = @received + 1 if finished? event.receiver.close event.connection.close end end end def finished? @received == @expected end end qpid-proton-0.14.0/examples/ruby/messenger/0000755000175000017500000000000012770711154020116 5ustar danieldanielqpid-proton-0.14.0/examples/ruby/messenger/README.md0000644000175000017500000001536012770711154021402 0ustar danieldaniel## Simple Messenger Examples The Messenger APIs, contained in the Qpid::Proton::Messenger class, represent the simplest means for sending and receive messages. An application need only create an instance of Messenger to have an endpoint for sending and receiving messages. Example applications, currently located in the messenger subdirectory, include: * **send.rb** - Sends one or more messages to a specific address. * **recv.rb** - Listens for messages sent to one or more addresses. ### Sending A Simple Message Directly (Without A Broker) The goal of this example is to demonstrate how to send and receive messages directly between applications. To do that we've broken out the examples into two applciations: **send.rb** and **recv.rb**. First we need to start the receiver who will listen for an incoming connection: ``` $ ruby recv.rb ~0.0.0.0:8888 ``` **NOTE:** Be sure to include the **tilda (~)** at the beginning of each address to be used. This tells the Messenger that it's going to be listening for connections on that port. And be sure to pick a free port for each of the addresses used. Now you can send messages with: ``` $ ruby send.rb -a 0.0.0.0:8888 "Hello world" ``` **NOTE:** Here you *don't* use a **tilda (~)** at the beginning of the address since you're specifying the receiver address rather than the address on which to listen. On the receiver side you should see something like: ``` Address: 0.0.0.0:8888 Subject: How are you? Body: This is a test. Properties: {"sent"=>1432651492, "hostname"=>"mcpierce-laptop"} Instructions: {"fold"=>"yes", "spindle"=>"no", "mutilate"=>"no"} Annotations: {"version"=>1.0, "pill"=>"RED"} ``` This tells us the message we received as expected. ### Sending A Simple Message Through A Broker To send a message via an intermediary, such as the Qpid broker, we need to give both the sender and the receiver a little bit more information, such as the hostname and port for the broker and the name of the queue where messages will be sent and received. If you're using the Qpid broker, this can be done using the **qpid-config** tool. Simply start your broker and then create our queue, which we'll call "examples": ``` $ qpid-config add queue examples ``` As of this point you can begin sending messages *without* starting the receiver. This is the benefit of using a broker, the ability to have something store messages for retrieval. Now let's send a bunch of messages to the queue using **send.rb**: ``` $ for which in $(seq 1 10); do ruby send.rb --address amqp://localhost/examples "This is test ${which}."; done ``` This example sends 10 messages to the our queue on the broker, where they will stay until retrieved. With this scenario we needed to specify the hostname of the broker and also the name of the queue in the address. After the sending completes you can verify the content of the queue using the **qpid-stat** command: ``` $ qpid-stat -q Queues queue dur autoDel excl msg msgIn msgOut bytes bytesIn bytesOut cons bind ========================================================================================================================= examples 10 10 0 2.65k 2.65k 0 0 1 fa4b8acb-03b6-4cff-9277-eeb2efe3c88a:0.0 Y Y 0 0 0 0 0 0 1 2 ``` Now to retrieve the messages. Start the **recv.rb** example using: ``` $ ruby recv.rb "amqp://127.0.0.1:5672/examples" ``` Once it connects to the broker, it will subscribe to the queue and begin receiving messages. You should see something like the following: ``` Address: amqp://localhost/examples Subject: How are you? Body: This is test 1. Properties: {"sent"=>1432837902, "hostname"=>"mcpierce-laptop"} Instructions: {"fold"=>"yes", "spindle"=>"no", "mutilate"=>"no"} Annotations: {"version"=>1.0, "pill"=>"RED"} Address: amqp://localhost/examples Subject: How are you? Body: This is test 2. Properties: {"sent"=>1432837903, "hostname"=>"mcpierce-laptop"} Instructions: {"fold"=>"yes", "spindle"=>"no", "mutilate"=>"no"} Annotations: {"version"=>1.0, "pill"=>"RED"} Address: amqp://localhost/examples Subject: How are you? Body: This is test 3. ... truncating the remainder of the output ... ``` As with the sending, we specific the protocol to use and the address and port on the host to connect to the broker. ## Non-Blocking Receive With The Messenger APIs One of the downsides of Messenger is that, out of the box, it's a blocking set of APIs; i.e., when attempting to receive messages the Ruby VM is halted until the call returns. Enter **non-blocking mode**! When working in non-blocking mode you set a flag on your messenger to put it into non-blocking mode. ``` messenger = Qpid::Proton::Messenger.new messenger.passive = true ``` At this point the application is responsible for monitoring the set of file descriptors associated with those Messengers. It takes a little more code but the benefit is that the application can spawn this in a separate thread and not have the entire VM block during I/O operations. The **nonblocking_recv.rb** example app demonstrates how to perform this properly, how to wrap the file descriptor in a Selectable type, monitor it for when there's data to send or receive and then work with the instance of Messenger. For more details on how to do this, take a look at the comments in the example application. ### Running The Non-Blocking Receiver To start the non-blocking receiver, simply start the example application like this: ``` $ ruby nonblocking_recv.rb ~0.0.0.0:8888 This is a side thread: The time is now 11:39:24. The time is now 11:39:25. The time is now 11:39:26. ``` As the receiver runs it outputs the current time every second to show that a separate thread is running. Now you can launch the **client.rb** example to send a message to the receiver and then wait for a reply: ``` $ ruby client.rb -r "~/#" 0.0.0.0:8888 "This is a test." "Here is my message." amqp://c19f3e88-866a-46ae-8284-d229acf8a5cb/#, RE: This is a test. ``` As you see, in the command line we specify "~/#" as the address to which any reply should be sent. It's outside of the scope of this example, but the tilda (~) is expanded into a unique address by Proton and used for receiving any responses. On the receiver side you should see something like this: ``` The time is now 11:42:04. The time is now 11:42:05. The time is now 11:42:06. Address: 0.0.0.0:8888 Subject: This is a test. Body: Properties: {} Instructions: {} Annotations: {} === Sending a reply to amqp://c19f3e88-866a-46ae-8284-d229acf8a5cb/# The time is now 11:42:07. The time is now 11:42:08. ``` Notice in the receiver's output how the reply was sent to the address on the sender that was created by our specifying "~/#" qpid-proton-0.14.0/examples/ruby/messenger/client.rb0000644000175000017500000000422512770711154021724 0ustar danieldaniel#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'qpid_proton' require 'optparse' $options = { :verbose => false, :hostname => "0.0.0.0", :subject => "", :replyto => "~/replies" } OptionParser.new do |opts| opts.banner = "Usage: client [options] " opts.on("-r", "--reply-to", String, :REQUIRED, "Reply address") do |replyto| $options[:replyto] = replyto end opts.on("-v", "--verbose", :NONE, "Enable verbose output") do $options[:verbose] = true end opts.on("-h", "--help", :NONE, "Show this help message") do puts opts exit end begin ARGV << "-h" if ARGV.empty? opts.parse!(ARGV) rescue OptionParser::ParseError => error STDERR.puts error.message, "\n", opts exit 1 end ($options[:address], $options[:subject]) = ARGV abort "No address specified" if $options[:hostname].nil? abort "No subject specified" if $options[:subject].nil? end def log(text) printf "#{Time.new}: #{text}\n" if $options[:verbose] end msgr = Qpid::Proton::Messenger::Messenger.new msgr.start msg = Qpid::Proton::Message.new msg.address = $options[:address] msg.subject = $options[:subject] msg.reply_to = $options[:replyto] msgr.put(msg) msgr.send if $options[:replyto].start_with? "~/" msgr.receive(1) begin msgr.get(msg) puts "#{msg.address}, #{msg.subject}" rescue error puts error end end msgr.stop qpid-proton-0.14.0/examples/ruby/messenger/mailserver.rb0000644000175000017500000000417312770711154022621 0ustar danieldaniel#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'qpid_proton' require 'optparse' FAILED = 0 CONNECTION_UP = 1 AUTHENTICATING = 2 $options = { :verbose => false, :address => ["amqp://~0.0.0.0"], } OptionParser.new do |opts| opts.banner = "Usage: mailserver [options] ... " opts.on("-v", "--verbose", :NONE, "Print status messages to stdout") do |f| $options[:verbose] = true end opts.parse! if ARGV.length > 0 $options[:address] = [] ARGV.each {|address| $options[:address] << address} end end def log(text) STDOUT.puts "#{Time.new}: #{text}" if $options[:verbose] end msgr = Qpid::Proton::Messenger::Messenger.new msgr.start $options[:address].each {|addr| msgr.subscribe(addr)} def dispatch(request, response) response.subject = "Re: #{request.subject}" if !request.subject.empty? response.properties = request.properties puts "Dispatched #{request.subject} #{request.properties}" end msg = Qpid::Proton::Message.new reply = Qpid::Proton::Message.new loop do msgr.receive(10) if msgr.incoming < 10 if msgr.incoming > 0 msgr.get(msg) if !msg.reply_to.nil? && !msg.reply_to.empty? puts msg.reply_to reply.address = msg.reply_to reply.correlation_id = msg.correlation_id reply.body = msg.body end dispatch(msg, reply) msgr.put(reply) msgr.send end end msgr.stop qpid-proton-0.14.0/examples/ruby/messenger/nonblocking_recv.rb0000644000175000017500000000671412770711154023775 0ustar danieldaniel#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. require 'qpid_proton' require 'optparse' Thread.new do print "This is a side thread:\n" loop do print "The time is now #{Time.new.strftime('%I:%M:%S')}.\n" sleep 1 end end addresses = [] OptionParser.new do |opts| opts.banner = "Usage: recv.rb ... " opts.parse! addresses = ARGV end addresses = ["~0.0.0.0"] if addresses.empty? messenger = Qpid::Proton::Messenger::Messenger.new messenger.passive = true begin messenger.start rescue ProtonError => error print "ERROR: #{error.message}\n" print error.backtrace.join("\n") exit end addresses.each do |address| begin messenger.subscribe(address) rescue Qpid::Proton::ProtonError => error print "ERROR: #{error.message}\n" exit end end msg = Qpid::Proton::Message.new read_array = [] write_array = [] selectables = {} loop do # wait for incoming messages sel = messenger.selectable while !sel.nil? if sel.terminal? selectables.delete(sel.fileno) read_array.delete(sel) write_array.delete(sel) sel.free else if !sel.registered? read_array << sel write_array << sel selectables[sel.fileno] = sel sel.registered = true end end sel = messenger.selectable end unless selectables.empty? rarray = []; read_array.each {|fd| rarray << fd.to_io } warray = []; write_array.each {|fd| warray << fd.to_io } if messenger.deadline > 0.0 result = IO.select(rarray, warray, nil, messenger.deadline) else result = IO.select(rarray, warray) end unless result.nil? && result.empty? result.flatten.each do |io| sel = selectables[io.fileno] sel.writable sel.readable end end begin messenger.receive(10) rescue Qpid::Proton::ProtonError => error print "ERROR: #{error.message}\n" exit end while messenger.incoming.nonzero? begin messenger.get(msg) rescue Qpid::Proton::Error => error print "ERROR: #{error.message}\n" exit end print "Address: #{msg.address}\n" subject = msg.subject || "(no subject)" print "Subject: #{subject}\n" print "Body: #{msg.body}\n" print "Properties: #{msg.properties}\n" print "Instructions: #{msg.instructions}\n" print "Annotations: #{msg.annotations}\n" if msg.reply_to print "=== Sending a reply to #{msg.reply_to}\n" reply = Qpid::Proton::Message.new reply.address = msg.reply_to reply.subject = "RE: #{msg.subject}" reply.body = "Thanks for the message!" messenger.put(reply) messenger.send end end end end messenger.stop qpid-proton-0.14.0/examples/ruby/messenger/recv.rb0000644000175000017500000000373712770711154021414 0ustar danieldaniel#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. require 'qpid_proton' require 'optparse' addresses = [] OptionParser.new do |opts| opts.banner = "Usage: recv.rb ... " opts.parse! addresses = ARGV end addresses = ["~0.0.0.0"] if addresses.empty? messenger = Qpid::Proton::Messenger::Messenger.new begin messenger.start rescue ProtonError => error puts "ERROR: #{error.message}" puts error.backtrace.join("\n") exit end addresses.each do |address| begin messenger.subscribe(address) rescue Qpid::Proton::ProtonError => error puts "ERROR: #{error.message}" exit end end msg = Qpid::Proton::Message.new loop do begin messenger.receive(10) rescue Qpid::Proton::ProtonError => error puts "ERROR: #{error.message}" exit end while messenger.incoming.nonzero? begin messenger.get(msg) rescue Qpid::Proton::Error => error puts "ERROR: #{error.message}" exit end puts "Address: #{msg.address}" subject = msg.subject || "(no subject)" puts "Subject: #{subject}" puts "Body: #{msg.body}" puts "Properties: #{msg.properties}" puts "Instructions: #{msg.instructions}" puts "Annotations: #{msg.annotations}" end end messenger.stop qpid-proton-0.14.0/examples/ruby/messenger/send.rb0000644000175000017500000000372112770711154021377 0ustar danieldaniel#!/usr/bin/env ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. require 'qpid_proton' require 'optparse' options = {} messages = [] OptionParser.new do |opts| opts.banner = "Usage: send.rb [options] ... " opts.on("-a", "--address [addr]", "The receiver's address (def. 0.0.0.0)") do |f| options[:address] = f end opts.parse! messages = ARGV end options[:address] = "0.0.0.0" unless options[:address] messages << "Hello world!" if messages.empty? messenger = Qpid::Proton::Messenger::Messenger.new messenger.start msg = Qpid::Proton::Message.new messages.each do |message| msg.address = options[:address] msg.subject = "How are you?" msg["sent"] = Time.new msg["hostname"] = ENV["HOSTNAME"] msg.instructions["fold"] = "yes" msg.instructions["spindle"] = "no" msg.instructions["mutilate"] = "no" msg.annotations["version"] = 1.0 msg.annotations["pill"] = :RED msg.body = message begin messenger.put(msg) rescue Qpid::Proton::ProtonError => error puts "ERROR: #{error.message}" exit end end begin messenger.send rescue Qpid::Proton::ProtonError => error puts "ERROR: #{error.message}" puts error.backtrace.join("\n") exit end puts "SENT: " + messages.join(",") messenger.stop qpid-proton-0.14.0/examples/ruby/reactor/0000755000175000017500000000000012770711154017565 5ustar danieldanielqpid-proton-0.14.0/examples/ruby/reactor/README.md0000644000175000017500000001332512770711154021050 0ustar danieldaniel## What Is The Reactor? A little outside of the scope of this document, but the reactor is an event source for letting an application know about events in the Proton messaging system. With this set of APIs an application can be register handlers that are notified when a connection is created, a message received, or a session closes. ### Handlers An application creates **handlers**, objects which provide methods through which the reactor notifies the application's components of events and allows them each to handle the ones in which they are interested (see the Chain Of Responsibility design pattern for more on this idea). There are some pre-defined handlers for responding to incoming message events, outgoing message events, data flow and managing the AMQP endpoints. Look in the **Qpid::Proton::Handlers** package for more details on these classes. ## Simple Reactor Examples ### The Broker The reactor examples come with a sample broker which can be used by other examples and which also works as an example itself. For now we'll just start up the broker example and tell it to listen on port 8888: ```` $ ruby ../examples/ruby/reactor/broker.rb --address=0.0.0.0:8888 Listening on 0.0.0.0:8888 ```` This example broker will receive messages, create queues as needed, and deliver messages to endpoints. ### Hello World Using A Broker Our first example creates an endpoint that sends messages to a queue to which it is subscribed. So it both sends and receives its message in one pass. To start it, simply run: ``` $ ruby ../examples/ruby/reactor/helloworld.rb --address=0.0.0.0:8888 --queue=examples Hello world! ``` As you can see, the classic message was output by the example. Now let's take a look at what's going on under the covers. #### Events When Talking To A Broker The following events occur while **helloworld.rb** runs: * **on_start** - Fired when the application is started. * **on_sendable** - Fired when a message can be sent. * **on_message** - Fired when a message is received. ### Hello World Without A Broker required The next example we'll look at will send the classic "Hello world" message to itself directly. This example shows some very fundamental elements of the reactor APIs that you should understand. To launch the example: ``` $ ruby helloworld_direct.rb --address=0.0.0.0:8888/examples Hello world! ``` Not very different from the example that uses the broker, which is what we'd expect from the outside. But let's take a look inside of the example and see how it's different at that level The direct version takes on the responsibility for listening to incoming connections as well as making an outgoing connection. So we see the following additional events occurring: * **on_accepted** - Fired when a message is received. * **on_connection_closed** - Fired when an endpoint closes its connection. ## More Complex Reactor Examples Now that we've covered the basics with the archetypical hello world app, let's look at some more interesting examples. There are four example applications that demonstrate how to send and receive messages both directly and through an intermediary, such as a broker: * **simple_send.rb** - sends messages to a receiver at a specific address and receives responses via an intermediary, * **simple_recv.rb** - receives messages from via an intermediary, * **direct_send.rb** - sends messages directly to a receiver and listens for responses itself, and * **direct_recv.rb** - receives messages directly. Simple send and direct send may, at first, seem to be so similar that you wonder why they're not just the same applciation. And I know for me I was wonder as I wrote the list above why there were two examples. The reason is that **simple_send.rb** uses the intermediary transfer responses to the messages it sends, while **direct_send.rb** uses an *Acceptor* to listen for an process responses. You can use the examples in the follow ways: ``` simple_send.rb -> broker <- simple_recv.rb simple_send.rb -> direct_recv.rb direct_send.rb -> simple_recv.rb ``` In this set of examples we see the following event occurring, in addition to what we've seen before: * **on_disconnected** - Fired when the transport is closed. ## Now About That Broker example The **broker.rb** example application is a nice demonstration of doing something more interesting in Ruby with Proton. The way the broker works is to listen to incoming connections, examine the components of the address for that connection, attach that connection to an exchange managing that address and then it sends any messages destined for that address to them. The components of the broker example include: * **Broker** - A class that extends the MessagingHandler class. It accepts incoming connections, manages subscribing them to exchanges, and transfers messages between them. * **Exchange** - A class that represents a message queue, tracking what endpoints are subscribed to it. The Broker manages a map connecting a queue address to the instance of Exchange that holds references to the endpoints of interest. The broker application demonstrates a new set of reactor events: * **on_link_opening** - Fired when a remote link is opened but the local end is not yet open. From this event the broker grabs the address and subscribes the link to an exchange for that address. * **on_link_closing** - Fired when a remote link is closed but the local end is still open. From this event the broker grabs the address and unsubscribes the link from that exchange. * **on_connection_closing** - Fired when a remote connection is closed but the local end is still open. * **on_disconnected** - Fired when the protocol transport has closed. The broker removes all links for the disconnected connection, avoiding workign with endpoints that are now gone. qpid-proton-0.14.0/examples/ruby/reactor/direct_recv.rb0000644000175000017500000000330512770711154022404 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' require_relative '../lib/send_and_receive' class DirectReceive < ExampleReceive def initialize(url, expected) super end def on_start(event) @acceptor = event.container.listen(self.url) end def on_message(event) super(event) @acceptor.close if self.finished? end end options = { :address => "localhost:5672/examples", :messages => 100, } OptionParser.new do |opts| opts.banner = "Usage: simple_send.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") do |address| options[:address] = address end opts.on("-m", "--messages=COUNT", "The number of messages to send (def. #{options[:messages]}", OptionParser::DecimalInteger) do |messages| options[:messages] = messages end end.parse! Qpid::Proton::Reactor::Container.new(DirectReceive.new(options[:address], options[:messages])).run qpid-proton-0.14.0/examples/ruby/reactor/direct_send.rb0000644000175000017500000000325712770711154022404 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' require_relative '../lib/send_and_receive' options = { :address => "localhost:5672/examples", :messages => 100, } class SimpleSend < ExampleSend def initialize(url, messages) super(url, messages) end def on_start(event) @acceptor = event.container.listen(url) end end OptionParser.new do |opts| opts.banner = "Usage: simple_send.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") do |address| options[:address] = address end opts.on("-m", "--messages=COUNT", "The number of messages to send (def. #{options[:messages]}", OptionParser::DecimalInteger) do |messages| options[:messages] = messages end end.parse! begin Qpid::Proton::Reactor::Container.new(SimpleSend.new(options[:address], options[:messages])).run rescue Interrupt => error puts "ERROR: #{error}" end qpid-proton-0.14.0/examples/ruby/reactor/helloworld_direct.rb0000644000175000017500000000351212770711154023620 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' options = { :address => "localhost:5672/examples", } class HelloWorldDirect < Qpid::Proton::Handler::MessagingHandler include Qpid::Proton::Util::Wrapper def initialize(url) super() @url = url end def on_start(event) @acceptor = event.container.listen(@url) event.container.create_sender(@url) end def on_sendable(event) msg = Qpid::Proton::Message.new msg.body = "Hello world!" event.sender.send(msg) event.sender.close end def on_message(event) puts "#{event.message.body}" end def on_accepted(event) event.connection.close end def on_connection_closed(event) @acceptor.close end end OptionParser.new do |opts| opts.banner = "Usage: helloworld_direct.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") do |address| options[:address] = address end end.parse! begin Qpid::Proton::Reactor::Container.new(HelloWorldDirect.new(options[:address])).run rescue Interrupt => error end qpid-proton-0.14.0/examples/ruby/reactor/simple_recv.rb0000644000175000017500000000320412770711154022421 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' require_relative '../lib/send_and_receive' class Receiver < ExampleReceive def initialize(url, count) super(url, count) end def on_start(event) event.container.create_receiver(@url) end end options = { :address => "localhost:5672/examples", :messages => 100, } OptionParser.new do |opts| opts.banner = "Usage: simple_send.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") do |address| options[:address] = address end opts.on("-m", "--messages=COUNT", "The number of messages to send (def. #{options[:messages]}", OptionParser::DecimalInteger) do |messages| options[:messages] = messages end end.parse! begin Qpid::Proton::Reactor::Container.new(Receiver.new(options[:address], options[:messages])).run rescue Interrupt end qpid-proton-0.14.0/examples/ruby/reactor/simple_send.rb0000644000175000017500000000315312770711154022416 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' require_relative '../lib/send_and_receive' options = { :address => "localhost:5672/examples", :messages => 100, } class SimpleSend < ExampleSend def initialize(url, messages) super(url, messages) end def on_start(event) event.container.create_sender(url) end end OptionParser.new do |opts| opts.banner = "Usage: simple_send.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") do |address| options[:address] = address end opts.on("-m", "--messages=COUNT", "The number of messages to send (def. #{options[:messages]}", OptionParser::DecimalInteger) do |messages| options[:messages] = messages end end.parse! Qpid::Proton::Reactor::Container.new(SimpleSend.new(options[:address], options[:messages])).run qpid-proton-0.14.0/examples/ruby/reactor/broker.rb0000644000175000017500000001273712770711154021410 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' require 'pathname' require_relative '../lib/debugging' class Exchange include Debugging def initialize(dynamic = false) @dynamic = dynamic @queue = Queue.new @consumers = [] end def subscribe(consumer) debug("subscribing #{consumer}") if $options[:debug] @consumers << (consumer) debug(" there are #{@consumers.size} consumers") if $options[:debug] end def unsubscribe(consumer) debug("unsubscribing #{consumer}") if $options[:debug] if @consumers.include?(consumer) @consumers.delete(consumer) else debug(" consumer doesn't exist") if $options[:debug] end debug(" there are #{@consumers.size} consumers") if $options[:debug] @consumers.empty? && (@dynamic || @queue.empty?) end def publish(message) debug("queueing message: #{message.body}") if $options[:debug] @queue << message self.dispatch end def dispatch(consumer = nil) debug("dispatching: consumer=#{consumer}") if $options[:debug] if consumer c = [consumer] else c = @consumers end while self.deliver_to(c) do end end def deliver_to(consumers) debug("delivering to #{consumers.size} consumer(s)") if $options[:debug] result = false consumers.each do |consumer| debug(" current consumer=#{consumer} credit=#{consumer.credit}") if $options[:debug] if consumer.credit > 0 && !@queue.empty? consumer.send(@queue.pop(true)) result = true end end return result end end class Broker < Qpid::Proton::Handler::MessagingHandler include Debugging def initialize(url) super() @url = url @queues = {} end def on_start(event) debug("on_start event") if $options[:debug] @acceptor = event.container.listen(@url) print "Listening on #{@url}\n" end def queue(address) debug("fetching queue for #{address}: (there are #{@queues.size} queues)") if $options[:debug] unless @queues.has_key?(address) debug(" creating new queue") if $options[:debug] @queues[address] = Exchange.new else debug(" using existing queue") if $options[:debug] end result = @queues[address] debug(" returning #{result}") if $options[:debug] return result end def on_link_opening(event) debug("processing on_link_opening") if $options[:debug] debug("link is#{event.link.sender? ? '' : ' not'} a sender") if $options[:debug] if event.link.sender? if event.link.remote_source.dynamic? address = SecureRandom.uuid event.link.source.address = address q = Exchange.new(true) @queues[address] = q q.subscribe(event.link) elsif event.link.remote_source.address event.link.source.address = event.link.remote_source.address self.queue(event.link.source.address).subscribe(event.link) end elsif event.link.remote_target.address event.link.target.address = event.link.remote_target.address end end def unsubscribe(link) debug("unsubscribing #{link.address}") if $options[:debug] if @queues.has_key?(link.source.address) if @queues[link.source.address].unsubscribe(link) @queues.delete(link.source.address) end end end def on_link_closing(event) self.unsubscribe(event.link) if event.link.sender? end def on_connection_closing(event) self.remove_stale_consumers(event.connection) end def on_disconnected(event) self.remove_stale_consumers(event.connection) end def remove_stale_consumers(connection) l = connection.link_head(Qpid::Proton::Endpoint::REMOTE_ACTIVE) while !l.nil? self.unsubscribe(l) if l.sender? l = l.next(Qpid::Proton::Endpoint::REMOTE_ACTIVE) end end def on_sendable(event) debug("on_sendable event") if $options[:debug] q = self.queue(event.link.source.address) debug(" dispatching #{event.message} to #{q}") if $options[:debug] q.dispatch(event.link) end def on_message(event) debug("on_message event") if $options[:debug] q = self.queue(event.link.target.address) debug(" dispatching #{event.message} to #{q}") if $options[:debug] q.publish(event.message) end end $options = { :address => "localhost:5672", :debug => false } OptionParser.new do |opts| opts.banner = "Usage: #{Pathname.new(__FILE__).basename} [$options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{$options[:address]}).") do |address| $options[:address] = address end opts.on("-d", "--debug", "Enable debugging output (def. #{$options[:debug]})") do $options[:debug] = true end end.parse! begin Qpid::Proton::Reactor::Container.new(Broker.new($options[:address])).run rescue Interrupt end qpid-proton-0.14.0/examples/ruby/reactor/client.rb0000644000175000017500000000443012770711154021371 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' class Client < Qpid::Proton::Handler::MessagingHandler def initialize(url, requests) super() @url = url @requests = requests end def on_start(event) @sender = event.container.create_sender(@url) @receiver = event.container.create_receiver(@sender.connection, :dynamic => true) end def next_request if @receiver.remote_source.address req = Qpid::Proton::Message.new req.reply_to = @receiver.remote_source.address req.body = @requests.first puts "-> #{req.body}" @sender.send(req) end end def on_link_opened(event) if event.receiver == @receiver next_request end end def on_message(event) puts "<- #{event.message.body}" @requests.delete_at(0) if !@requests.empty? next_request else event.connection.close end end def on_transport_error(event) raise "Connection error: #{event.transport.condition}" end end REQUESTS = ["Twas brillig, and the slithy toves", "Did gire and gymble in the wabe.", "All mimsy were the borogroves,", "And the mome raths outgrabe."] options = { :address => "localhost:5672/examples", } OptionParser.new do |opts| opts.banner = "Usage: client.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") { |address| options[:address] = address } end.parse! Qpid::Proton::Reactor::Container.new(Client.new(options[:address], REQUESTS)).run qpid-proton-0.14.0/examples/ruby/reactor/helloworld.rb0000644000175000017500000000403512770711154022267 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' class HelloWorld < Qpid::Proton::Handler::MessagingHandler def initialize(server, address) super() @server = server @address = address end def on_start(event) conn = event.container.connect(:address => @server) event.container.create_sender(conn, :target => @address) event.container.create_receiver(conn, :source => @address) end def on_sendable(event) msg = Qpid::Proton::Message.new msg.body = "Hello world!" event.sender.send(msg) event.sender.close end def on_message(event) puts event.message.body event.connection.close end def on_transport_error(event) raise "Connection error: #{event.transport.condition}" end end options = { :address => "localhost:5672", :queue => "examples" } OptionParser.new do |opts| opts.banner = "Usage: helloworld_direct.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") do |address| options[:address] = address end opts.on("-q", "--queue=QUEUE", "Send messages to QUEUE (def. #{options[:queue]})") do |queue| options[:queue] = queue end end.parse! hw = HelloWorld.new(options[:address], "examples") Qpid::Proton::Reactor::Container.new(hw).run qpid-proton-0.14.0/examples/ruby/reactor/server.rb0000644000175000017500000000447012770711154021425 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'optparse' class Server < Qpid::Proton::Handler::MessagingHandler def initialize(url) super() @url = Qpid::Proton::URL.new url @address = @url.path @senders = {} end def on_start(event) @container = event.container @conn = @container.connect(:url => @url) @receiver = @container.create_receiver(@conn, :source => @address) @relay = nil end def on_connection_opened(event) if event.connection.remote_offered_capabilities && event.connection.remote_offered_capabilities.contain?("ANONYMOUS-RELAY") @relay = @container.create_sender(@conn, nil) end end def on_message(event) msg = event.message puts "<- #{msg.body}" sender = @relay || @senders[msg.reply_to] if sender.nil? sender = @container.create_sender(@conn, :target => msg.reply_to) @senders[msg.reply_to] = sender end reply = Qpid::Proton::Message.new reply.address = msg.reply_to reply.body = msg.body.upcase puts "-> #{reply.body}" reply.correlation_id = msg.correlation_id sender.send(reply) end def on_transport_error(event) raise "Connection error: #{event.transport.condition}" end end options = { :address => "localhost:5672/examples", } OptionParser.new do |opts| opts.banner = "Usage: server.rb [options]" opts.on("-a", "--address=ADDRESS", "Send messages to ADDRESS (def. #{options[:address]}).") { |address| options[:address] = address } end.parse! Qpid::Proton::Reactor::Container.new(Server.new(options[:address])).run() qpid-proton-0.14.0/examples/ruby/registry_test.rb0000644000175000017500000000417212770711154021366 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' require 'weakref' def show_registry(registry) registry.each_pair do |key, value| registry.delete(key) if value.weakref_alive? end puts "The contents of the registry: size=#{registry.size}" end def show_object_count(clazz) puts "There are #{ObjectSpace.each_object(clazz).count} instances of #{clazz}." end impl = Cproton.pn_transport implclazz = impl.class transport = Qpid::Proton::Transport.wrap(impl) puts "Initial setup:" show_object_count(Qpid::Proton::Transport) show_object_count(implclazz) transport = nil show_registry(Qpid::Proton.registry) ObjectSpace.garbage_collect puts "After garbage collection:" show_object_count(Qpid::Proton::Transport) show_object_count(implclazz) MAXCOUNT=100000 (1..MAXCOUNT).each do |which| nimpl = Cproton.pn_transport Cproton.pn_incref(nimpl) transport = Qpid::Proton::Transport.wrap(nimpl) transport = Qpid::Proton::Transport.wrap(nimpl) end transport = nil puts "After creating #{MAXCOUNT} instances" show_object_count(Qpid::Proton::Transport) show_object_count(implclazz) show_registry(Qpid::Proton.registry) ObjectSpace.garbage_collect transport = Qpid::Proton::Transport.wrap(impl) puts "After garbage collection:" puts "impl=#{impl}" puts "transport=#{transport}" show_object_count(Qpid::Proton::Transport) show_object_count(implclazz) show_registry(Qpid::Proton.registry) qpid-proton-0.14.0/examples/ruby/wrapper_test.rb0000644000175000017500000000515412770711154021177 0ustar danieldaniel#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. #++ require 'qpid_proton' def how_many_transports?(expected) count = ObjectSpace.each_object(Qpid::Proton::Transport).count if expected.min == expected.max expectation = "#{expected.min}" else expectation = "#{expected.min} <= count <= #{expected.max}" end puts "Transport count: found #{count}, expected #{expectation} (#{expected.include?(count) ? 'Good' : 'Bad'})" end transport = Qpid::Proton::Transport.new timpl = transport.impl puts "=================================" puts "= Storing my original transport =" puts "=================================" puts " Stored transport=#{transport} (#{Cproton.pni_address_of(timpl).to_s(16)})" how_many_transports?(1..1) puts "=================================" transport.instance_eval { @first_name = "Darryl"; @last_name = "Pierce", @instance_id = 717 } transport = nil puts "" max = 1000 puts "Creating #{max} instances of Transport" (0...max).each do |which| t = Qpid::Proton::Transport.new t.instance_eval { @instance_id = which } t = nil end puts "" puts "====================================" puts "= Retrieving my original transport =" puts "====================================" transport = Qpid::Proton::Transport.wrap(timpl) puts "Retrieved transport=#{transport} (#{Cproton.pni_address_of(timpl).to_s(16)})" how_many_transports?(1..1001) puts "====================================" puts "My transport attributes:" puts transport transport = nil GC.start how_many_transports?(1..1) puts "" puts "======================================" puts "= Throwing away the Transport object =" puts "======================================" transport = nil timpl.instance_eval { @proton_wrapper = nil } GC.start begin transport = Qpid::Proton::Transport.wrap(timpl) puts "!!! This should fail!" rescue Qpid::Proton::ProtonError => error puts "Good, it failed..." end how_many_transports?(0..0) qpid-proton-0.14.0/examples/ruby/example_test.rb0000755000175000017500000000471412770711154021156 0ustar danieldaniel#!/usr/bin/enc ruby # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # require 'test/unit' require 'qpid_proton' require 'socket' $port = Random.new.rand(10000) + 10000 class ExampleTest < Test::Unit::TestCase def run_script(script, port) assert File.exist? script cmd = [RbConfig.ruby, script] cmd += ["-a", ":#{port}/examples"] if port return IO.popen(cmd) end def assert_output(script, want, port=nil) out = run_script(script, port) assert_equal want, out.read.strip end def test_helloworld assert_output("reactor/helloworld.rb", "Hello world!", $port) end def test_send_recv assert_output("reactor/simple_send.rb", "All 100 messages confirmed!", $port) want = (0..99).reduce("") { |x,y| x << "Received: sequence #{y}\n" } assert_output("reactor/simple_recv.rb", want.strip, $port) end def test_client_server want = < Twas brillig, and the slithy toves <- TWAS BRILLIG, AND THE SLITHY TOVES -> Did gire and gymble in the wabe. <- DID GIRE AND GYMBLE IN THE WABE. -> All mimsy were the borogroves, <- ALL MIMSY WERE THE BOROGROVES, -> And the mome raths outgrabe. <- AND THE MOME RATHS OUTGRABE. EOS srv = run_script("reactor/server.rb", $port) assert_output("reactor/client.rb", want.strip, $port) ensure Process.kill :TERM, srv.pid if srv end end begin broker = spawn("#{RbConfig.ruby} reactor/broker.rb -a :#{$port}") # Wait for the broker to be listening. while true begin s = TCPSocket.open "", $port puts "Broker ready at #{$port}" s.close break rescue Errno::ECONNREFUSED puts "Retry connection to #{$port}" sleep(0.1) end end Test::Unit::AutoRunner.run ensure Process.kill :TERM, broker if broker end qpid-proton-0.14.0/examples/CMakeLists.txt0000644000175000017500000000171412770711155017711 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # set (Proton_DIR ${CMAKE_CURRENT_SOURCE_DIR}) set (ProtonCpp_DIR ${CMAKE_CURRENT_SOURCE_DIR}) add_subdirectory(c) add_subdirectory(go) if (BUILD_CPP) add_subdirectory(cpp) endif() qpid-proton-0.14.0/examples/ProtonConfig.cmake0000644000175000017500000000263512770711155020565 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Note that this file is used *only* when building the examples within # the proton source tree not when the examples are installed separately # from it (for example in an OS distribution package). # # So if you find this file installed on your system something went wrong # with the packaging and/or package installation. # # For a packaged installation the equivalent file is created by the source # tree build and installed in the appropriate place for cmake on that system. set (Proton_VERSION ${PN_VERSION}) set (Proton_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/proton-c/include) set (Proton_LIBRARIES qpid-proton) set (Proton_FOUND True) qpid-proton-0.14.0/examples/ProtonCppConfig.cmake0000644000175000017500000000273712770711155021233 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Note that this file is used *only* when building the examples within # the proton source tree not when the examples are installed separately # from it (for example in an OS distribution package). # # So if you find this file installed on your system something went wrong # with the packaging and/or package installation. # # For a packaged installation the equivalent file is created by the source # tree build and installed in the appropriate place for cmake on that system. set (ProtonCpp_VERSION ${PN_VERSION}) set (ProtonCpp_INCLUDE_DIRS ${CMAKE_SOURCE_DIR}/proton-c/include ${CMAKE_SOURCE_DIR}/proton-c/bindings/cpp/include) set (ProtonCpp_LIBRARIES qpid-proton-cpp) set (ProtonCpp_FOUND True) qpid-proton-0.14.0/examples/cpp/0000755000175000017500000000000012770711155015730 5ustar danieldanielqpid-proton-0.14.0/examples/cpp/CMakeLists.txt0000644000175000017500000000511612770711155020473 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # find_package(ProtonCpp REQUIRED) include_directories(${ProtonCpp_INCLUDE_DIRS}) link_libraries(${ProtonCpp_LIBRARIES}) add_definitions(${CXX_WARNING_FLAGS}) # Add a test with the correct environment to find test executables and valgrind. macro(add_cpp_test name) if(WIN32) set(test_path "$;$;$") else(WIN32) set(test_path "$:$ENV{PATH}") endif(WIN32) set(run_env ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py) add_test(NAME ${name} COMMAND ${run_env} "PATH=${test_path}" ${VALGRIND_ENV} -- ${ARGN}) endmacro() # Single-threaded examples that work on C++03 foreach(example broker helloworld helloworld_direct simple_recv simple_send scheduled_send_03 direct_recv direct_send client server server_direct connection_options queue_browser selected_recv flow_control ssl ssl_client_cert service_bus encode_decode) add_executable(${example} ${example}.cpp) endforeach() if(HAS_CPP11) # Single-threaded examples that require C++11 foreach(example scheduled_send) add_executable(${example} ${example}.cpp) endforeach() # Linux-only multi-threaded examples (TODO make these portable) if(CMAKE_SYSTEM_NAME STREQUAL "Linux") set(container_src mt/epoll_container.cpp) foreach(example broker) add_executable(mt_${example} mt/${example}.cpp ${container_src}) target_link_libraries(mt_${example} pthread) endforeach() add_cpp_test(cpp_mt_example_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v MtBrokerTest) endif() endif() add_cpp_test(cpp_container_example_test ${PYTHON_EXECUTABLE} ${CMAKE_CURRENT_SOURCE_DIR}/example_test.py -v ContainerExampleTest) qpid-proton-0.14.0/examples/cpp/README.dox0000644000175000017500000001136112770711155017403 0ustar danieldaniel// C++ examples list (doxygen format) // // For a tutorial-style description of the examples see tutorial.dox. // To build the full HTML tutorial and documentation, in your build directory do: // // make docs-cpp // // then open proton-c/bindings/cpp/docs/html/tutorial.html in your browser. // DEVELOPER NOTE: if you add or modify examples, please add/update a short // description below and (if appropriate) extend/update tutorial.dox. /** example sub directory The example sub-directory has utilities classes to make the example simpler, these classes are not directly related to the use of proton so are in a separate `example` directory and namespace. */ /** @example helloworld.cpp Connects to a broker on 127.0.0.1:5672, establishes a subscription from the 'examples' node, and creates a sending link to the same node. Sends one message and receives it back. */ /** @example helloworld_direct.cpp Variation of helloworld that does not use a broker, but listens for incoming connections itself. It establishes a connection to itself with a link over which a single message is sent. This demonstrates the ease with which a simple daemon an be built using the API. */ /** @example simple_send.cpp An example of sending a fixed number of messages and tracking their (asynchronous) acknowledgement. Messages are sent through the 'examples' node on an intermediary accessible on 127.0.0.1:5672. */ /** @example simple_recv.cpp Subscribes to the 'examples' node on an intermediary accessible on 127.0.0.1:5672. Simply prints out the body of received messages. */ /** @example direct_send.cpp Accepts an incoming connection and then sends like `simple_send`. You can connect directly to `direct_send` *without* a broker using @ref simple_recv.cpp. Make sure to stop the broker first or use a different port for `direct_send`. */ /** @example direct_recv.cpp Accepts an incoming connection and then receives like `simple_recv`. You can connect directly to `direct_recv` *without* a broker using @ref simple_send.cpp. Make sure to stop the broker first or use a different port for `direct_recv`. */ /// @cond INTERNAL /** @example encode_decode.cpp Shows how C++ data types can be converted to and from AMQP types. */ /// @endcond /** @example client.cpp The client part of a request-response example. Sends requests and prints out responses. Requires an intermediary that supports the AMQP 1.0 dynamic nodes on which the responses are received. The requests are sent through the 'examples' node. */ /** @example server.cpp The server part of a request-response example, that receives requests via the examples node, converts the body to uppercase and sends the result back to the indicated reply address. */ /** @example server_direct.cpp A variant of the server part of a request-response example that accepts incoming connections and does not need an intermediary. Much like the original server, it receives incoming requests, converts the body to uppercase and sends the result back to the indicated reply address. Can be used in conjunction with any of the client alternatives. */ /** @example broker.hpp Common logic for a simple "mini broker" that creates creates queues automatically when a client tries to send or subscribe. This file contains the `queue` class that queues messages and the `broker_handler` class that manages queues and links and transfers messages to/from clients. */ /** @example broker.cpp A simple, single-threaded broker using the `proton::container`. You can use this to run other examples that reqiure an intermediary, or you can use any AMQP 1.0 broker. This broker creates queues automatically when a client tries to send or subscribe. */ /** @example mt/epoll_container.cpp An example implementation of the proton::container API that shows how to use the proton::io::connection_engine SPI to adapt the proton API to native IO, in this case using a multithreaded Linux epoll poller as the implementation. __Requires C++11__ */ /** @example mt/broker.cpp A multithreaded broker, that will work on any multi-threaded container. See @ref mt/epoll_container.cpp for an example of a multi-threaded container. __Requires C++11__ */ /** @example schedule_send.cpp Shows how to use proton::container::schedule to schedule a timed callback. This version uses std::function and so requires C++11 or better. For a C++03 compatible approach see @ref schedule_send_03.cpp. */ /** @example schedule_send_03.cpp Shows how to use proton::container::schedule to schedule a timed callback in a C++03 compatible way. See @ref schedule_send.cpp for a more convenient approach using std::function if you have C++11. */ /** @example service_bus.cpp A working example for accessing Service Bus session-enabled queues. Also provides some general notes on Service Bus usage. */ qpid-proton-0.14.0/examples/cpp/broker.cpp0000644000175000017500000001713412770711155017726 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" /// A simple implementation of a queue. class queue { public: queue(const std::string &name, bool dynamic = false) : name_(name), dynamic_(dynamic) {} std::string name() const { return name_; } void subscribe(proton::sender s) { consumers_.push_back(s); } // Return true if queue can be deleted. bool unsubscribe(proton::sender s) { consumers_.remove(s); return (consumers_.size() == 0 && (dynamic_ || messages_.size() == 0)); } void publish(const proton::message &m) { messages_.push_back(m); dispatch(0); } void dispatch(proton::sender *s) { while (deliver_to(s)) {} } bool deliver_to(proton::sender *s) { // Deliver to single sender if supplied, else all consumers int count = s ? 1 : consumers_.size(); if (!count) return false; bool result = false; sender_list::iterator it = consumers_.begin(); if (!s && count) { s = &*it; } while (messages_.size()) { if (s->credit()) { const proton::message& m = messages_.front(); s->send(m); messages_.pop_front(); result = true; } if (--count) { it++; } else { return result; } } return false; } private: typedef std::deque message_queue; typedef std::list sender_list; std::string name_; bool dynamic_; message_queue messages_; sender_list consumers_; }; /// A collection of queues and queue factory, used by a broker. class queues { public: queues() : next_id_(0) {} virtual ~queues() {} // Get or create a queue. virtual queue &get(const std::string &address) { if (address.empty()) { throw std::runtime_error("empty queue name"); } queue*& q = queues_[address]; if (!q) q = new queue(address); return *q; } // Create a dynamic queue with a unique name. virtual queue &dynamic() { std::ostringstream os; os << "q" << next_id_++; queue *q = queues_[os.str()] = new queue(os.str(), true); return *q; } // Delete the named queue virtual void erase(std::string &name) { delete queues_[name]; queues_.erase(name); } protected: typedef std::map queue_map; queue_map queues_; uint64_t next_id_; // Use to generate unique queue IDs. }; // A handler to implement broker logic class broker_handler : public proton::messaging_handler { public: broker_handler(queues& qs) : queues_(qs) {} void on_sender_open(proton::sender &sender) OVERRIDE { proton::source src(sender.source()); queue *q; if (src.dynamic()) { q = &queues_.dynamic(); } else if (!src.address().empty()) { q = &queues_.get(src.address()); } else { sender.close(proton::error_condition("No queue address supplied")); return; } sender.open(proton::sender_options().source(proton::source_options().address(q->name()))); q->subscribe(sender); std::cout << "broker outgoing link from " << q->name() << std::endl; } void on_receiver_open(proton::receiver &receiver) OVERRIDE { std::string address = receiver.target().address(); if (!address.empty()) { receiver.open(proton::receiver_options().target(proton::target_options().address(address))); std::cout << "broker incoming link to " << address << std::endl; } else { receiver.close(proton::error_condition("No queue address supplied")); } } void unsubscribe(proton::sender lnk) { std::string address = lnk.source().address(); if (queues_.get(address).unsubscribe(lnk)) { queues_.erase(address); } } void on_sender_close(proton::sender &sender) OVERRIDE { unsubscribe(sender); } void on_connection_close(proton::connection &c) OVERRIDE { remove_stale_consumers(c); } void on_transport_close(proton::transport &t) OVERRIDE { remove_stale_consumers(t.connection()); } void on_transport_error(proton::transport &t) OVERRIDE { std::cout << "broker client disconnect: " << t.error().what() << std::endl; } void on_error(const proton::error_condition &c) OVERRIDE { std::cerr << "broker error: " << c.what() << std::endl; } void remove_stale_consumers(proton::connection connection) { proton::sender_range r = connection.senders(); for (proton::sender_iterator i = r.begin(); i != r.end(); ++i) { if (i->active()) unsubscribe(*i); } } void on_sendable(proton::sender &s) OVERRIDE { std::string address = s.source().address(); queues_.get(address).dispatch(&s); } void on_message(proton::delivery &d, proton::message &m) OVERRIDE { std::string address = d.receiver().target().address(); queues_.get(address).publish(m); } protected: queues& queues_; }; // The broker class broker { public: broker(const std::string& url) : handler_(url, queues_) {} proton::messaging_handler& handler() { return handler_; } private: class my_handler : public broker_handler { public: my_handler(const std::string& u, queues& qs) : broker_handler(qs), url_(u) {} void on_container_start(proton::container &c) OVERRIDE { c.listen(url_); std::cout << "broker listening on " << url_ << std::endl; } private: const std::string& url_; }; private: queues queues_; my_handler handler_; }; int main(int argc, char **argv) { std::string url("0.0.0.0"); example::options opts(argc, argv); opts.add_value(url, 'a', "address", "listen on URL", "URL"); try { opts.parse(); broker b(url); proton::default_container(b.handler()).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/broker.hpp0000644000175000017500000001516412770711155017734 0ustar danieldaniel#ifndef BROKER_HPP #define BROKER_HPP /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT 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 /// /// Common code used by different broker examples. /// /// The examples add functionality as needed, this helps to make it /// easier to see the important differences between the examples. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /// A simple implementation of a queue. class queue { public: queue(const std::string &name, bool dynamic = false) : name_(name), dynamic_(dynamic) {} std::string name() const { return name_; } void subscribe(proton::sender s) { consumers_.push_back(s); } // Return true if queue can be deleted. bool unsubscribe(proton::sender s) { consumers_.remove(s); return (consumers_.size() == 0 && (dynamic_ || messages_.size() == 0)); } void publish(const proton::message &m) { messages_.push_back(m); dispatch(0); } void dispatch(proton::sender *s) { while (deliver_to(s)) {} } bool deliver_to(proton::sender *s) { // Deliver to single sender if supplied, else all consumers int count = s ? 1 : consumers_.size(); if (!count) return false; bool result = false; sender_list::iterator it = consumers_.begin(); if (!s && count) { s = &*it; } while (messages_.size()) { if (s->credit()) { const proton::message& m = messages_.front(); s->send(m); messages_.pop_front(); result = true; } if (--count) { it++; } else { return result; } } return false; } private: typedef std::deque message_queue; typedef std::list sender_list; std::string name_; bool dynamic_; message_queue messages_; sender_list consumers_; }; /// A collection of queues and queue factory, used by a broker. class queues { public: queues() : next_id_(0) {} virtual ~queues() {} // Get or create a queue. virtual queue &get(const std::string &address = std::string()) { if (address.empty()) { throw std::runtime_error("empty queue name"); } queue*& q = queues_[address]; if (!q) q = new queue(address); return *q; } // Create a dynamic queue with a unique name. virtual queue &dynamic() { std::ostringstream os; os << "q" << next_id_++; queue *q = queues_[os.str()] = new queue(os.str(), true); return *q; } // Delete the named queue virtual void erase(std::string &name) { delete queues_[name]; queues_.erase(name); } protected: typedef std::map queue_map; queue_map queues_; uint64_t next_id_; // Use to generate unique queue IDs. }; #include /** Common handler logic for brokers. */ class broker_handler : public proton::messaging_handler { public: broker_handler(queues& qs) : queues_(qs) {} void on_transport_open(proton::transport &t) OVERRIDE { std::cout << "Connection from user: " << t.sasl().user() << " (mechanism: " << t.sasl().mech() << ")" << std::endl; } void on_sender_open(proton::sender &sender) OVERRIDE { proton::source src(sender.source()); queue &q = src.dynamic() ? queues_.dynamic() : queues_.get(src.address()); sender.open(proton::sender_options().source(proton::source_options().address(q.name()))); q.subscribe(sender); std::cout << "broker outgoing link from " << q.name() << std::endl; } void on_receiver_open(proton::receiver &receiver) OVERRIDE { std::string address = receiver.target().address(); if (!address.empty()) { receiver.open(proton::receiver_options().target(proton::target_options().address(address))); std::cout << "broker incoming link to " << address << std::endl; } } void unsubscribe(proton::sender lnk) { std::string address = lnk.source().address(); if (queues_.get(address).unsubscribe(lnk)) { queues_.erase(address); } } void on_sender_close(proton::sender &sender) OVERRIDE { unsubscribe(sender); } void on_connection_close(proton::connection &c) OVERRIDE { remove_stale_consumers(c); } void on_transport_close(proton::transport &t) OVERRIDE { remove_stale_consumers(t.connection()); } void on_transport_error(proton::transport &t) OVERRIDE { std::cout << "broker client disconnect: " << t.error().what() << std::endl; } void on_error(const proton::error_condition &c) OVERRIDE { std::cerr << "broker error: " << c.what() << std::endl; } void remove_stale_consumers(proton::connection connection) { proton::sender_range sr = connection.senders(); for (proton::sender_iterator i = sr.begin(); i != sr.end(); ++i) { if (i->active()) unsubscribe(*i); } } void on_sendable(proton::sender &s) OVERRIDE { std::string address = s.source().address(); queues_.get(address).dispatch(&s); } void on_message(proton::delivery &d, proton::message &m) OVERRIDE { std::string address = d.receiver().target().address(); queues_.get(address).publish(m); } protected: queues& queues_; }; #endif // BROKER_HPP qpid-proton-0.14.0/examples/cpp/client.cpp0000644000175000017500000000640412770711155017716 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" using proton::receiver_options; using proton::source_options; class client : public proton::messaging_handler { private: std::string url; std::vector requests; proton::sender sender; proton::receiver receiver; public: client(const std::string &u, const std::vector& r) : url(u), requests(r) {} void on_container_start(proton::container &c) OVERRIDE { sender = c.open_sender(url); // Create a receiver requesting a dynamically created queue // for the message source. receiver_options opts = receiver_options().source(source_options().dynamic(true)); receiver = sender.connection().open_receiver("", opts); } void send_request() { proton::message req; req.body(requests.front()); req.reply_to(receiver.source().address()); sender.send(req); } void on_receiver_open(proton::receiver &) OVERRIDE { send_request(); } void on_message(proton::delivery &d, proton::message &response) OVERRIDE { if (requests.empty()) return; // Spurious extra message! std::cout << requests.front() << " => " << response.body() << std::endl; requests.erase(requests.begin()); if (!requests.empty()) { send_request(); } else { d.connection().close(); } } }; int main(int argc, char **argv) { std::string url("127.0.0.1:5672/examples"); example::options opts(argc, argv); opts.add_value(url, 'a', "address", "connect and send to URL", "URL"); try { opts.parse(); std::vector requests; requests.push_back("Twas brillig, and the slithy toves"); requests.push_back("Did gire and gymble in the wabe."); requests.push_back("All mimsy were the borogroves,"); requests.push_back("And the mome raths outgrabe."); client c(url, requests); proton::default_container(c).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/connection_options.cpp0000644000175000017500000000513512770711155022352 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include using proton::connection_options; #include "fake_cpp11.hpp" class handler_2 : public proton::messaging_handler { void on_connection_open(proton::connection &c) OVERRIDE { std::cout << "connection events going to handler_2" << std::endl; std::cout << "connection max_frame_size: " << c.max_frame_size() << ", idle timeout: " << c.idle_timeout() << std::endl; c.close(); } }; class main_handler : public proton::messaging_handler { private: std::string url; handler_2 conn_handler; public: main_handler(const std::string& u) : url(u) {} void on_container_start(proton::container &c) OVERRIDE { // Connection options for this connection. Merged with and overriding the container's // client_connection_options() settings. c.connect(url, connection_options().handler(conn_handler).max_frame_size(2468)); } void on_connection_open(proton::connection &c) OVERRIDE { std::cout << "unexpected connection event on main handler" << std::endl; c.close(); } }; int main(int argc, char **argv) { try { std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples"; main_handler handler(url); proton::default_container container(handler); // Global connection options for future connections on container. container.client_connection_options(connection_options().max_frame_size(12345).idle_timeout(proton::duration(15000))); container.run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/direct_recv.cpp0000644000175000017500000000521512770711155020730 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" class direct_recv : public proton::messaging_handler { private: std::string url; proton::listener listener; uint64_t expected; uint64_t received; public: direct_recv(const std::string &s, int c) : url(s), expected(c), received(0) {} void on_container_start(proton::container &c) OVERRIDE { listener = c.listen(url); std::cout << "direct_recv listening on " << url << std::endl; } void on_message(proton::delivery &d, proton::message &msg) OVERRIDE { if (proton::coerce(msg.id()) < received) { return; // Ignore duplicate } if (expected == 0 || received < expected) { std::cout << msg.body() << std::endl; received++; } if (received == expected) { d.receiver().close(); d.connection().close(); listener.stop(); } } }; int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); int message_count = 100; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "listen and receive on URL", "URL"); opts.add_value(message_count, 'm', "messages", "receive COUNT messages", "COUNT"); try { opts.parse(); direct_recv recv(address, message_count); proton::default_container(recv).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/direct_send.cpp0000644000175000017500000000552012770711155020721 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include "fake_cpp11.hpp" class simple_send : public proton::messaging_handler { private: std::string url; proton::listener listener; int sent; int confirmed; int total; public: simple_send(const std::string &s, int c) : url(s), sent(0), confirmed(0), total(c) {} void on_container_start(proton::container &c) OVERRIDE { listener = c.listen(url); std::cout << "direct_send listening on " << url << std::endl; } void on_sendable(proton::sender &sender) OVERRIDE { while (sender.credit() && sent < total) { proton::message msg; std::map m; m["sequence"] = sent + 1; msg.id(sent + 1); msg.body(m); sender.send(msg); sent++; } } void on_tracker_accept(proton::tracker &t) OVERRIDE { confirmed++; if (confirmed == total) { std::cout << "all messages confirmed" << std::endl; t.connection().close(); listener.stop(); } } void on_transport_close(proton::transport &) OVERRIDE { sent = confirmed; } }; int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); int message_count = 100; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "listen and send on URL", "URL"); opts.add_value(message_count, 'm', "messages", "send COUNT messages", "COUNT"); try { opts.parse(); simple_send send(address, message_count); proton::default_container(send).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/encode_decode.cpp0000644000175000017500000001773112770711155021205 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include #include #include // Examples of how to use the encoder and decoder to create and examine AMQP values. // // Print is defined at the end as an example of how to query and extract complex // values from a decoder in terms of their simple components. void print(proton::value&); // Some helper templates to print map and std::vector results. namespace std { template ostream& operator<<(ostream& o, const std::pair& p) { return o << p.first << ":" << p.second; } template ostream& operator<<(ostream& o, const std::vector& v) { o << "[ "; ostream_iterator oi(o, " "); copy(v.begin(), v.end(), oi); return o << "]"; } template ostream& operator<<(ostream& o, const std::list& v) { o << "[ "; ostream_iterator oi(o, " "); copy(v.begin(), v.end(), oi); return o << "]"; } template ostream& operator<<(ostream& o, const map& m) { o << "{ "; ostream_iterator > oi(o, " "); copy(m.begin(), m.end(), oi); return o << "}"; } } // Insert/extract native C++ containers with uniform type values. static void uniform_containers() { std::cout << std::endl << "== Array, list and map of uniform type." << std::endl; proton::value v; std::vector a; a.push_back(1); a.push_back(2); a.push_back(3); // By default a C++ container is encoded as an AMQP array. v = a; print(v); std::list a1; proton::get(v, a1); std::cout << a1 << std::endl; // You can specify that a container should be encoded as an AMQP list instead. v = proton::codec::encoder::list(a1); print(v); std::cout << proton::get >(v) << std::endl; // C++ map types (types with key_type, mapped_type) convert to an AMQP map by default. std::map m; m["one"] = 1; m["two"] = 2; v = m; print(v); std::cout << proton::get >(v) << std::endl; // A sequence of pairs encodes as an AMQP MAP, which lets you control the encoded order. std::vector > pairs; pairs.push_back(std::make_pair("z", 3)); pairs.push_back(std::make_pair("a", 4)); v = pairs; print(v); // You can also decode an AMQP map as a sequence of pairs to preserve encode order. std::vector > pairs2; proton::codec::decoder d(v); d >> pairs2; std::cout << pairs2 << std::endl; // A vector of proton::value is normally encoded as a mixed-type AMQP LIST, // but you can encoded it as an array provided all the values match the array type. std::vector vv; vv.push_back(proton::value("a")); vv.push_back(proton::value("b")); vv.push_back(proton::value("c")); v = vv; print(v); } // Containers with mixed types use value to represent arbitrary AMQP types. static void mixed_containers() { std::cout << std::endl << "== List and map of mixed type values." << std::endl; proton::value v; std::vector l; l.push_back(proton::value(42)); l.push_back(proton::value(std::string("foo"))); // By default, a sequence of proton::value is treated as an AMQP list. v = l; print(v); std::vector l2 = proton::get >(v); std::cout << l2 << std::endl; std::map m; m[proton::value("five")] = proton::value(5); m[proton::value(4)] = proton::value("four"); v = m; print(v); typedef std::map value_map; value_map m2(proton::get(v)); std::cout << m2 << std::endl; } // Insert using stream operators (see print_next for example of extracting with stream ops.) static void insert_stream_operators() { std::cout << std::endl << "== Insert with stream operators." << std::endl; proton::value v; // Create an array of INT with values [1, 2, 3] proton::codec::encoder e(v); e << proton::codec::start::array(proton::INT) << int32_t(1) << int32_t(2) << int32_t(3) << proton::codec::finish(); print(v); // Create a mixed-type list of the values [42, 0, "x"]. proton::codec::encoder e2(v); e2 << proton::codec::start::list() << int32_t(42) << false << proton::symbol("x") << proton::codec::finish(); print(v); // Create a map { "k1":42, "k2": false } proton::codec::encoder e3(v); e3 << proton::codec::start::map() << "k1" << int32_t(42) << proton::symbol("k2") << false << proton::codec::finish(); print(v); } int main(int, char**) { try { uniform_containers(); mixed_containers(); insert_stream_operators(); return 0; } catch (const std::exception& e) { std::cerr << std::endl << "error: " << e.what() << std::endl; } return 1; } // print_next prints the next value from values by recursively descending into complex values. // // NOTE this is for example puroses only: There is a built in ostream operator<< for values. // // static void print_next(proton::codec::decoder& d) { proton::type_id type = d.next_type(); proton::codec::start s; switch (type) { case proton::ARRAY: { d >> s; std::cout << "array<" << s.element; if (s.is_described) { std::cout << ", descriptor="; print_next(d); } std::cout << ">["; for (size_t i = 0; i < s.size; ++i) { if (i) std::cout << ", "; print_next(d); } std::cout << "]"; d >> proton::codec::finish(); break; } case proton::LIST: { d >> s; std::cout << "list["; for (size_t i = 0; i < s.size; ++i) { if (i) std::cout << ", "; print_next(d); } std::cout << "]"; d >> proton::codec::finish(); break; } case proton::MAP: { d >> s; std::cout << "map{"; for (size_t i = 0; i < s.size/2; ++i) { if (i) std::cout << ", "; print_next(d); std::cout << ":"; // key:value print_next(d); } std::cout << "}"; d >> proton::codec::finish(); break; } case proton::DESCRIBED: { d >> s; std::cout << "described("; print_next(d); // Descriptor print_next(d); // value d >> proton::codec::finish(); break; } default: // A simple type. We could continue the switch for all AMQP types but // we will take a short cut and extract to another value and print that. proton::value v2; d >> v2; std::cout << type << "(" << v2 << ")"; } } // Print a value, for example purposes. Normal code can use operator<< void print(proton::value& v) { proton::codec::decoder d(v); d.rewind(); while (d.more()) { print_next(d); if (d.more()) std::cout << ", "; } std::cout << std::endl; } qpid-proton-0.14.0/examples/cpp/example_test.py0000644000175000017500000004133512770711155021002 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 is a test script to run the examples and verify that they behave as expected. import unittest import os, sys, socket, time, re, inspect from random import randrange from subprocess import Popen, PIPE, STDOUT, call from copy import copy import platform from os.path import dirname as dirname from threading import Thread, Event from string import Template createdSASLDb = False def findfileinpath(filename, searchpath): """Find filename in the searchpath return absolute path to the file or None """ paths = searchpath.split(os.pathsep) for path in paths: if os.path.exists(os.path.join(path, filename)): return os.path.abspath(os.path.join(path, filename)) return None def _cyrusSetup(conf_dir): """Write out simple SASL config. """ saslpasswd = "" if 'SASLPASSWD' in os.environ: saslpasswd = os.environ['SASLPASSWD'] else: saslpasswd = findfileinpath('saslpasswd2', os.getenv('PATH')) or "" if os.path.exists(saslpasswd): t = Template("""sasldb_path: ${db} mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS """) abs_conf_dir = os.path.abspath(conf_dir) call(args=['rm','-rf',abs_conf_dir]) os.mkdir(abs_conf_dir) db = os.path.join(abs_conf_dir,'proton.sasldb') conf = os.path.join(abs_conf_dir,'proton-server.conf') f = open(conf, 'w') f.write(t.substitute(db=db)) f.close() cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user") cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd) call(args=cmd, shell=True) os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir global createdSASLDb createdSASLDb = True # Globally initialize Cyrus SASL configuration #if SASL.extended(): _cyrusSetup('sasl_conf') def ensureCanTestExtendedSASL(): # if not SASL.extended(): # raise Skipped('Extended SASL not supported') if not createdSASLDb: raise Skipped("Can't Test Extended SASL: Couldn't create auth db") def pick_addr(): """Pick a new host:port address.""" # TODO Conway 2015-07-14: need a safer way to pick ports. p = randrange(10000, 20000) return "127.0.0.1:%s" % p class ProcError(Exception): """An exception that captures failed process output""" def __init__(self, proc, what="non-0 exit"): out = proc.out.strip() if out: out = "\nvvvvvvvvvvvvvvvv\n%s\n^^^^^^^^^^^^^^^^\n" % out else: out = ", no output)" super(Exception, self, ).__init__( "%s %s, code=%s%s" % (proc.args, what, proc.returncode, out)) class Proc(Popen): """A example process that stores its stdout and can scan it for a 'ready' pattern'""" if "VALGRIND" in os.environ and os.environ["VALGRIND"]: env_args = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--leak-check=full"] else: env_args = [] def __init__(self, args, ready=None, timeout=30, skip_valgrind=False, **kwargs): """Start an example process""" args = list(args) if platform.system() == "Windows": args[0] += ".exe" self.timeout = timeout self.args = args self.out = "" if not skip_valgrind: args = self.env_args + args try: Popen.__init__(self, args, stdout=PIPE, stderr=STDOUT, universal_newlines=True, **kwargs) except Exception as e: raise ProcError(self, str(e)) # Start reader thread. self.pattern = ready self.ready = Event() # Help with Python 2.5, 2.6, 2.7 changes to Event.wait(), Event.is_set self.ready_set = False self.error = None self.thread = Thread(target=self.run_) self.thread.daemon = True self.thread.start() if self.pattern: self.wait_ready() def run_(self): try: while True: l = self.stdout.readline() if not l: break self.out += l if self.pattern is not None: if re.search(self.pattern, l): self.ready_set = True self.ready.set() if self.wait() != 0: raise ProcError(self) except Exception as e: self.error = e finally: self.stdout.close() self.ready_set = True self.ready.set() def safe_kill(self): """Kill and clean up zombie but don't wait forever. No exceptions.""" try: self.kill() self.thread.join(self.timeout) except: pass return self.out def check_(self): if self.error: raise self.error def wait_ready(self): """Wait for ready to appear in output""" self.ready.wait(self.timeout) if self.ready_set: self.check_() return self.out else: self.safe_kill() raise ProcError(self, "timeout waiting for '%s'" % self.pattern) def wait_exit(self): """Wait for process to exit, return output. Raise ProcError on failure.""" self.thread.join(self.timeout) if self.poll() is not None: self.check_() return self.out else: raise ProcError(self, "timeout waiting for exit") if hasattr(unittest.TestCase, 'setUpClass') and hasattr(unittest.TestCase, 'tearDownClass'): TestCase = unittest.TestCase else: class TestCase(unittest.TestCase): """ Roughly provides setUpClass and tearDownClass functionality for older python versions in our test scenarios. If subclasses override setUp or tearDown they *must* call the superclass. """ def setUp(self): if not hasattr(type(self), '_setup_class_count'): type(self)._setup_class_count = len( inspect.getmembers( type(self), predicate=lambda m: inspect.ismethod(m) and m.__name__.startswith('test_'))) type(self).setUpClass() def tearDown(self): self.assertTrue(self._setup_class_count > 0) self._setup_class_count -= 1 if self._setup_class_count == 0: type(self).tearDownClass() class ExampleTestCase(TestCase): """TestCase that manages started processes""" def setUp(self): super(ExampleTestCase, self).setUp() self.procs = [] def tearDown(self): for p in self.procs: p.safe_kill() super(ExampleTestCase, self).tearDown() def proc(self, *args, **kwargs): p = Proc(*args, **kwargs) self.procs.append(p) return p class BrokerTestCase(ExampleTestCase): """ ExampleTest that starts a broker in setUpClass and kills it in tearDownClass. Subclasses must set `broker_exe` class variable with the name of the broker executable. """ @classmethod def setUpClass(cls): cls.addr = pick_addr() + "/examples" cls.broker = None # In case Proc throws, create the attribute. cls.broker = Proc([cls.broker_exe, "-a", cls.addr], ready="listening") cls.broker.wait_ready() @classmethod def tearDownClass(cls): if cls.broker: cls.broker.safe_kill() def tearDown(self): b = type(self).broker if b and b.poll() != None: # Broker crashed type(self).setUpClass() # Start another for the next test. raise ProcError(b, "broker crash") super(BrokerTestCase, self).tearDown() CLIENT_EXPECT="""Twas brillig, and the slithy toves => TWAS BRILLIG, AND THE SLITHY TOVES Did gire and gymble in the wabe. => DID GIRE AND GYMBLE IN THE WABE. All mimsy were the borogroves, => ALL MIMSY WERE THE BOROGROVES, And the mome raths outgrabe. => AND THE MOME RATHS OUTGRABE. """ def recv_expect(name, addr): return "%s listening on %s\n%s" % ( name, addr, "".join(['{"sequence"=%s}\n' % (i+1) for i in range(100)])) class ContainerExampleTest(BrokerTestCase): """Run the container examples, verify they behave as expected.""" broker_exe = "broker" def test_helloworld(self): self.assertEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit()) def test_helloworld_direct(self): self.assertEqual('Hello World!\n', self.proc(["helloworld_direct", pick_addr()]).wait_exit()) def test_simple_send_recv(self): self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit()) self.assertEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit()) def test_simple_recv_send(self): # Start receiver first, then run sender""" recv = self.proc(["simple_recv", "-a", self.addr]) self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit()) self.assertEqual(recv_expect("simple_recv", self.addr), recv.wait_exit()) def test_simple_send_direct_recv(self): addr = pick_addr() recv = self.proc(["direct_recv", "-a", addr], "listening") self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", addr]).wait_exit()) self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit()) def test_simple_recv_direct_send(self): addr = pick_addr() send = self.proc(["direct_send", "-a", addr], "listening") self.assertEqual(recv_expect("simple_recv", addr), self.proc(["simple_recv", "-a", addr]).wait_exit()) self.assertEqual( "direct_send listening on %s\nall messages confirmed\n" % addr, send.wait_exit()) def test_request_response(self): server = self.proc(["server", "-a", self.addr], "connected") self.assertEqual(CLIENT_EXPECT, self.proc(["client", "-a", self.addr]).wait_exit()) def test_request_response_direct(self): addr = pick_addr() server = self.proc(["server_direct", "-a", addr+"/examples"], "listening") self.assertEqual(CLIENT_EXPECT, self.proc(["client", "-a", addr+"/examples"]).wait_exit()) def test_flow_control(self): want="""success: Example 1: simple credit success: Example 2: basic drain success: Example 3: drain without credit success: Exmaple 4: high/low watermark """ self.assertEqual(want, self.proc(["flow_control", "--address", pick_addr(), "--quiet"]).wait_exit()) def test_encode_decode(self): want=""" == Array, list and map of uniform type. array[int(1), int(2), int(3)] [ 1 2 3 ] list[int(1), int(2), int(3)] [ 1 2 3 ] map{string(one):int(1), string(two):int(2)} { one:1 two:2 } map{string(z):int(3), string(a):int(4)} [ z:3 a:4 ] list[string(a), string(b), string(c)] == List and map of mixed type values. list[int(42), string(foo)] [ 42 foo ] map{int(4):string(four), string(five):int(5)} { 4:four five:5 } == Insert with stream operators. array[int(1), int(2), int(3)] list[int(42), boolean(0), symbol(x)] map{string(k1):int(42), symbol(k2):boolean(0)} """ self.maxDiff = None self.assertEqual(want, self.proc(["encode_decode"]).wait_exit()) def ssl_certs_dir(self): """Absolute path to the test SSL certificates""" pn_root = dirname(dirname(dirname(sys.argv[0]))) return os.path.join(pn_root, "examples/cpp/ssl_certs") def test_ssl(self): # SSL without SASL, VERIFY_PEER_NAME addr = "amqps://" + pick_addr() + "/examples" # Disable valgrind when using OpenSSL out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir()], skip_valgrind=True).wait_exit() expect = "Outgoing client connection connected via SSL. Server certificate identity CN=test_server\nHello World!" expect_found = (out.find(expect) >= 0) self.assertEqual(expect_found, True) def test_ssl_no_name(self): # VERIFY_PEER addr = "amqps://" + pick_addr() + "/examples" # Disable valgrind when using OpenSSL out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), "-v", "noname"], skip_valgrind=True).wait_exit() expect = "Outgoing client connection connected via SSL. Server certificate identity CN=test_server\nHello World!" expect_found = (out.find(expect) >= 0) self.assertEqual(expect_found, True) def test_ssl_bad_name(self): # VERIFY_PEER addr = "amqps://" + pick_addr() + "/examples" # Disable valgrind when using OpenSSL out = self.proc(["ssl", "-a", addr, "-c", self.ssl_certs_dir(), "-v", "fail"], skip_valgrind=True).wait_exit() expect = "Expected failure of connection with wrong peer name" expect_found = (out.find(expect) >= 0) self.assertEqual(expect_found, True) def test_ssl_client_cert(self): # SSL with SASL EXTERNAL expect="""Inbound client certificate identity CN=test_client Outgoing client connection connected via SSL. Server certificate identity CN=test_server Hello World! """ addr = "amqps://" + pick_addr() + "/examples" # Disable valgrind when using OpenSSL out = self.proc(["ssl_client_cert", addr, self.ssl_certs_dir()], skip_valgrind=True).wait_exit() expect_found = (out.find(expect) >= 0) self.assertEqual(expect_found, True) def test_scheduled_send_03(self): # Output should be a bunch of "send" lines but can't guarantee exactly how many. out = self.proc(["scheduled_send_03", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split() self.assertTrue(len(out) > 0); self.assertEqual(["send"]*len(out), out) def test_scheduled_send(self): try: out = self.proc(["scheduled_send", "-a", self.addr+"scheduled_send", "-t", "0.1", "-i", "0.001"]).wait_exit().split() self.assertTrue(len(out) > 0); self.assertEqual(["send"]*len(out), out) except ProcError: # File not found, not a C++11 build. pass class EngineTestCase(BrokerTestCase): """Run selected clients to test a connction_engine broker.""" def test_helloworld(self): self.assertEqual('Hello World!\n', self.proc(["helloworld", self.addr]).wait_exit()) def test_simple_send_recv(self): self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit()) self.assertEqual(recv_expect("simple_recv", self.addr), self.proc(["simple_recv", "-a", self.addr]).wait_exit()) def test_simple_recv_send(self): # Start receiver first, then run sender""" recv = self.proc(["simple_recv", "-a", self.addr]) self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", self.addr]).wait_exit()) self.assertEqual(recv_expect("simple_recv", self.addr), recv.wait_exit()) def test_simple_send_direct_recv(self): addr = pick_addr() recv = self.proc(["direct_recv", "-a", addr], "listening") self.assertEqual("all messages confirmed\n", self.proc(["simple_send", "-a", addr]).wait_exit()) self.assertEqual(recv_expect("direct_recv", addr), recv.wait_exit()) def test_simple_recv_direct_send(self): addr = pick_addr() send = self.proc(["direct_send", "-a", addr], "listening") self.assertEqual(recv_expect("simple_recv", addr), self.proc(["simple_recv", "-a", addr]).wait_exit()) self.assertEqual("direct_send listening on %s\nall messages confirmed\n" % addr, send.wait_exit()) def test_request_response(self): server = self.proc(["server", "-a", self.addr], "connected") self.assertEqual(CLIENT_EXPECT, self.proc(["client", "-a", self.addr]).wait_exit()) class MtBrokerTest(EngineTestCase): broker_exe = "mt_broker" if __name__ == "__main__": unittest.main() qpid-proton-0.14.0/examples/cpp/fake_cpp11.hpp0000644000175000017500000000215612770711155020357 0ustar danieldaniel#ifndef FAKE_CPP11_HPP #define FAKE_CPP11_HPP /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ /// These definitions allow us to use some new C++11 features in previous compilers /// /// It is strongly recommended not to copy this - just use C++11/C++14 instead! #if __cplusplus < 201103L #define OVERRIDE #else #define OVERRIDE override #endif #endif // FAKE_CPP11_HPP qpid-proton-0.14.0/examples/cpp/flow_control.cpp0000644000175000017500000001750112770711155021147 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" namespace { bool verbose = true; void verify(bool success, const std::string &msg) { if (!success) throw std::runtime_error("example failure:" + msg); else { std::cout << "success: " << msg << std::endl; if (verbose) std::cout << std::endl; } } } // flow_sender manages the incoming connection and acts as the message sender. class flow_sender : public proton::messaging_handler { private: int available; // Number of messages the sender may send assuming sufficient credit. int sequence; public: flow_sender() : available(0), sequence(0) {} void send_available_messages(proton::sender &s) { for (int i = sequence; available && s.credit() > 0; i++) { std::ostringstream mbody; mbody << "flow_sender message " << sequence++; proton::message m(mbody.str()); s.send(m); available--; } } void on_sendable(proton::sender &s) OVERRIDE { if (verbose) std::cout << "flow_sender in \"on_sendable\" with credit " << s.credit() << " and " << available << " available messages" << std::endl; send_available_messages(s); } void on_sender_drain_start(proton::sender &s) OVERRIDE { if (verbose) std::cout << "flow_sender in \"on_drain_start\" with credit " << s.credit() << " and " << available << " available messages" << std::endl; send_available_messages(s); if (s.credit()) { s.return_credit(); // return the rest } } void set_available(int n) { available = n; } }; class flow_receiver : public proton::messaging_handler { public: int stage; int received; flow_sender &sender; flow_receiver(flow_sender &s) : stage(0), received(0), sender(s) {} void example_setup(int n) { received = 0; sender.set_available(n); } void run_stage(proton::receiver &r, const std::string &caller) { // Serialize the progression of the flow control examples. switch (stage) { case 0: if (verbose) std::cout << "Example 1. Simple use of credit." << std::endl; // TODO: add timeout callbacks, show no messages until credit. example_setup(2); r.add_credit(2); break; case 1: if (r.credit() > 0) return; verify(received == 2, "Example 1: simple credit"); if (verbose) std::cout << "Example 2. Use basic drain, sender has 3 \"immediate\" messages." << std::endl; example_setup(3); r.add_credit(5); // ask for up to 5 r.drain(); // but only use what's available break; case 2: if (caller == "on_message") return; if (caller == "on_receiver_drain_finish") { // Note that unused credit of 2 at sender is returned and is now 0. verify(received == 3 && r.credit() == 0, "Example 2: basic drain"); if (verbose) std::cout << "Example 3. Drain use with no credit." << std::endl; example_setup(0); r.drain(); break; } verify(false, "example 2 run_stage"); return; case 3: verify(caller == "on_receiver_drain_finish" && received == 0, "Example 3: drain without credit"); if (verbose) std::cout << "Example 4. Show using high(10)/low(3) watermark for 25 messages." << std::endl; example_setup(25); r.add_credit(10); break; case 4: if (received < 25) { // Top up credit as needed. uint32_t credit = r.credit(); if (credit <= 3) { uint32_t new_credit = 10; uint32_t remaining = 25 - received; if (new_credit > remaining) new_credit = remaining; if (new_credit > credit) { r.add_credit(new_credit - credit); if (verbose) std::cout << "flow_receiver adding credit for " << new_credit - credit << " messages" << std::endl; } } return; } verify(received == 25 && r.credit() == 0, "Exmaple 4: high/low watermark"); r.connection().close(); break; default: throw std::runtime_error("run_stage sequencing error"); } stage++; } void on_receiver_open(proton::receiver &r) OVERRIDE { run_stage(r, "on_receiver_open"); } void on_message(proton::delivery &d, proton::message &m) OVERRIDE { if (verbose) std::cout << "flow_receiver in \"on_message\" with " << m.body() << std::endl; proton::receiver r(d.receiver()); received++; run_stage(r, "on_message"); } void on_receiver_drain_finish(proton::receiver &r) OVERRIDE { if (verbose) std::cout << "flow_receiver in \"on_receiver_drain_finish\"" << std::endl; run_stage(r, "on_receiver_drain_finish"); } }; class flow_control : public proton::messaging_handler { private: std::string url; proton::listener listener; flow_sender send_handler; flow_receiver receive_handler; public: flow_control(const std::string& u) : url(u), receive_handler(send_handler) {} void on_container_start(proton::container &c) OVERRIDE { listener = c.listen(url, proton::connection_options().handler(send_handler)); c.connect(url); } void on_connection_open(proton::connection &c) OVERRIDE { if (c.active()) { // outbound connection c.open_receiver("flow_example", proton::receiver_options().handler(receive_handler).credit_window(0)); } } void on_connection_close(proton::connection &) OVERRIDE { listener.stop(); } }; int main(int argc, char **argv) { // Pick an "unusual" port since we are going to be talking to // ourselves, not a broker. std::string address("127.0.0.1:8888"); bool quiet = false; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); opts.add_flag(quiet, 'q', "quiet", "suppress additional commentary of credit allocation and consumption"); try { opts.parse(); if (quiet) verbose = false; flow_control fc(address); proton::default_container(fc).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/helloworld.cpp0000644000175000017500000000376012770711155020615 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include #include "fake_cpp11.hpp" class hello_world : public proton::messaging_handler { private: proton::url url; public: hello_world(const std::string& u) : url(u) {} void on_container_start(proton::container& c) OVERRIDE { c.connect(url); } void on_connection_open(proton::connection& c) OVERRIDE { c.open_receiver(url.path()); c.open_sender(url.path()); } void on_sendable(proton::sender &s) OVERRIDE { proton::message m("Hello World!"); s.send(m); s.close(); } void on_message(proton::delivery &d, proton::message &m) OVERRIDE { std::cout << m.body() << std::endl; d.connection().close(); } }; int main(int argc, char **argv) { try { std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples"; hello_world hw(url); proton::default_container(hw).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/helloworld_direct.cpp0000644000175000017500000000431012770711155022137 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include #include "fake_cpp11.hpp" class hello_world_direct : public proton::messaging_handler { private: std::string url; proton::listener listener; public: hello_world_direct(const std::string& u) : url(u) {} void on_container_start(proton::container &c) OVERRIDE { listener = c.listen(url); c.open_sender(url); } void on_sendable(proton::sender &s) OVERRIDE { proton::message m("Hello World!"); s.send(m); s.close(); } void on_message(proton::delivery &, proton::message &m) OVERRIDE { std::cout << m.body() << std::endl; } void on_tracker_accept(proton::tracker &t) OVERRIDE { t.connection().close(); } void on_connection_close(proton::connection&) OVERRIDE { listener.stop(); } }; int main(int argc, char **argv) { try { // Pick an "unusual" port since we are going to be talking to // ourselves, not a broker. std::string url = argc > 1 ? argv[1] : "127.0.0.1:8888/examples"; hello_world_direct hwd(url); proton::default_container(hwd).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/mt/0000755000175000017500000000000012770711155016350 5ustar danieldanielqpid-proton-0.14.0/examples/cpp/mt/broker.cpp0000644000175000017500000002516412770711155020350 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "../options.hpp" #include "mt_container.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include "../fake_cpp11.hpp" // Thread safe queue. // Stores messages, notifies subscribed connections when there is data. class queue { public: queue(const std::string& name) : name_(name) {} std::string name() const { return name_; } // Push a message onto the queue. // If the queue was previously empty, notify subscribers it has messages. // Called from receiver's connection. void push(const proton::message &m) { std::lock_guard g(lock_); messages_.push_back(m); if (messages_.size() == 1) { // Non-empty, notify subscribers for (auto cb : callbacks_) cb(this); callbacks_.clear(); } } // If the queue is not empty, pop a message into m and return true. // Otherwise save callback to be called when there are messages and return false. // Called from sender's connection. bool pop(proton::message& m, std::function callback) { std::lock_guard g(lock_); if (messages_.empty()) { callbacks_.push_back(callback); return false; } else { m = std::move(messages_.front()); messages_.pop_front(); return true; } } private: const std::string name_; std::mutex lock_; std::deque messages_; std::vector > callbacks_; }; /// Thread safe map of queues. class queues { public: queues() : next_id_(0) {} // Get or create the named queue. queue* get(const std::string& name) { std::lock_guard g(lock_); auto i = queues_.insert(queue_map::value_type(name, nullptr)).first; if (!i->second) i->second.reset(new queue(name)); return i->second.get(); } // Create a dynamic queue with a unique name. queue* dynamic() { std::ostringstream os; os << "_dynamic_" << next_id_++; return get(os.str()); } private: typedef std::map > queue_map; std::mutex lock_; queue_map queues_; std::atomic next_id_; // Use to generate unique queue IDs. }; /// Broker connection handler. Things to note: /// /// 1. Each handler manages a single connection. /// /// 2. For a *single connection* calls to proton::handler functions and calls to /// function objects passed to proton::event_loop::inject() are serialized, /// i.e. never called concurrently. Handlers can have per-connection state /// without needing locks. /// /// 3. Handler/injected functions for *different connections* can be called /// concurrently. Resources used by multiple connections (e.g. the queues in /// this example) must be thread-safe. /// /// 4. You can 'inject' work to be done sequentially using a connection's /// proton::event_loop. In this example, we create a std::function callback /// that we pass to queues, so they can notify us when they have messages. /// class broker_connection_handler : public proton::messaging_handler { public: broker_connection_handler(queues& qs) : queues_(qs) {} void on_connection_open(proton::connection& c) OVERRIDE { // Create the has_messages callback for queue subscriptions. // // Make a std::shared_ptr to a thread_safe handle for our proton::connection. // The connection's proton::event_loop will remain valid as a shared_ptr exists. std::shared_ptr > ts_c = make_shared_thread_safe(c); // Make a lambda function to inject a call to this->has_messages() via the proton::event_loop. // The function is bound to a shared_ptr so this is safe. If the connection has already closed // proton::event_loop::inject() will drop the callback. has_messages_callback_ = [this, ts_c](queue* q) mutable { ts_c->event_loop()->inject( std::bind(&broker_connection_handler::has_messages, this, q)); }; c.open(); // Accept the connection } // A sender sends messages from a queue to a subscriber. void on_sender_open(proton::sender &sender) OVERRIDE { queue *q = sender.source().dynamic() ? queues_.dynamic() : queues_.get(sender.source().address()); std::cout << "sending from " << q->name() << std::endl; } // We have credit to send a message. void on_sendable(proton::sender &s) OVERRIDE { queue* q = sender_queue(s); if (!do_send(q, s)) // Queue is empty, save ourselves in the blocked set. blocked_.insert(std::make_pair(q, s)); } // A receiver receives messages from a publisher to a queue. void on_receiver_open(proton::receiver &r) OVERRIDE { std::string qname = r.target().address(); if (qname == "shutdown") { std::cout << "broker shutting down" << std::endl; // Sending to the special "shutdown" queue stops the broker. r.connection().container().stop( proton::error_condition("shutdown", "stop broker")); } else { std::cout << "receiving to " << qname << std::endl; } } // A message is received. void on_message(proton::delivery &d, proton::message &m) OVERRIDE { std::string qname = d.receiver().target().address(); queues_.get(qname)->push(m); } void on_session_close(proton::session &session) OVERRIDE { // Erase all blocked senders that belong to session. auto predicate = [session](const proton::sender& s) { return s.session() == session; }; erase_sender_if(blocked_.begin(), blocked_.end(), predicate); } void on_sender_close(proton::sender &sender) OVERRIDE { // Erase sender from the blocked set. auto range = blocked_.equal_range(sender_queue(sender)); auto predicate = [sender](const proton::sender& s) { return s == sender; }; erase_sender_if(range.first, range.second, predicate); } void on_error(const proton::error_condition& e) OVERRIDE { std::cerr << "error: " << e.what() << std::endl; } // The container calls on_transport_close() last. void on_transport_close(proton::transport&) OVERRIDE { delete this; // All done. } private: typedef std::multimap blocked_map; // Get the queue associated with a sender. queue* sender_queue(const proton::sender& s) { return queues_.get(s.source().address()); // Thread safe. } // Only called if we have credit. Return true if we sent a message. bool do_send(queue* q, proton::sender &s) { proton::message m; bool popped = q->pop(m, has_messages_callback_); if (popped) s.send(m); /// if !popped the queue has saved the callback for later. return popped; } // Called via the connection's proton::event_loop when q has messages. // Try all the blocked senders. void has_messages(queue* q) { auto range = blocked_.equal_range(q); for (auto i = range.first; i != range.second;) { if (i->second.credit() <= 0 || do_send(q, i->second)) i = blocked_.erase(i); // No credit or send was successful, stop blocked. else ++i; // have credit, didn't send, keep blocked } } // Use to erase closed senders from blocked_ set. template void erase_sender_if(blocked_map::iterator begin, blocked_map::iterator end, Predicate p) { for (auto i = begin; i != end; ) { if (p(i->second)) i = blocked_.erase(i); else ++i; } } queues& queues_; blocked_map blocked_; std::function has_messages_callback_; proton::connection connection_; }; class broker { public: broker(const std::string addr) : container_(make_mt_container("mt_broker")), listener_(queues_) { container_->listen(addr, listener_); std::cout << "broker listening on " << addr << std::endl; } void run() { std::vector threads(std::thread::hardware_concurrency()-1); for (auto& t : threads) t = std::thread(&proton::container::run, container_.get()); container_->run(); // Use this thread too. for (auto& t : threads) t.join(); } private: struct listener : public proton::listen_handler { listener(queues& qs) : queues_(qs) {} proton::connection_options on_accept() OVERRIDE{ return proton::connection_options().handler(*(new broker_connection_handler(queues_))); } void on_error(const std::string& s) OVERRIDE { std::cerr << "listen error: " << s << std::endl; throw std::runtime_error(s); } queues& queues_; }; queues queues_; std::unique_ptr container_; listener listener_; }; int main(int argc, char **argv) { // Command line options std::string address("0.0.0.0"); example::options opts(argc, argv); opts.add_value(address, 'a', "address", "listen on URL", "URL"); try { opts.parse(); broker(address).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << "broker shutdown: " << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/mt/epoll_container.cpp0000644000175000017500000003775412770711155022251 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include "mt_container.hpp" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include // Linux native IO #include #include #include #include #include #include #include #include "../fake_cpp11.hpp" // Private implementation namespace { using lock_guard = std::lock_guard; // Get string from errno std::string errno_str(const std::string& msg) { return std::system_error(errno, std::system_category(), msg).what(); } // Throw proton::error(errno_str(msg)) if result < 0 int check(int result, const std::string& msg) { if (result < 0) throw proton::error(errno_str(msg)); return result; } // Wrapper for getaddrinfo() that cleans up in destructor. class unique_addrinfo { public: unique_addrinfo(const std::string& addr) : addrinfo_(0) { proton::url u(addr); int result = ::getaddrinfo(char_p(u.host()), char_p(u.port()), 0, &addrinfo_); if (result) throw proton::error(std::string("bad address: ") + gai_strerror(result)); } ~unique_addrinfo() { if (addrinfo_) ::freeaddrinfo(addrinfo_); } ::addrinfo* operator->() const { return addrinfo_; } private: static const char* char_p(const std::string& s) { return s.empty() ? 0 : s.c_str(); } ::addrinfo *addrinfo_; }; // File descriptor wrapper that calls ::close in destructor. class unique_fd { public: unique_fd(int fd) : fd_(fd) {} ~unique_fd() { if (fd_ >= 0) ::close(fd_); } operator int() const { return fd_; } int release() { int ret = fd_; fd_ = -1; return ret; } protected: int fd_; }; class pollable; class pollable_engine; class pollable_listener; class epoll_container : public proton::io::container_impl_base { public: epoll_container(const std::string& id); ~epoll_container(); // Pull in base class functions here so that name search finds all the overloads using standard_container::stop; using standard_container::connect; using standard_container::listen; proton::returned connect( const std::string& addr, const proton::connection_options& opts) OVERRIDE; proton::listener listen(const std::string& addr, proton::listen_handler&) OVERRIDE; void stop_listening(const std::string& addr) OVERRIDE; void run() OVERRIDE; void auto_stop(bool) OVERRIDE; void stop(const proton::error_condition& err) OVERRIDE; std::string id() const OVERRIDE { return id_; } // Functions used internally. proton::connection add_engine(proton::connection_options opts, int fd, bool server); void erase(pollable*); // Link names must be unique per container. // Generate unique names with a simple atomic counter. class atomic_link_namer : public proton::io::link_namer { public: std::string link_name() { std::ostringstream o; o << std::hex << ++count_; return o.str(); } private: std::atomic count_; }; // FIXME aconway 2016-06-07: Unfinished void schedule(proton::duration, std::function) OVERRIDE { throw std::logic_error("FIXME"); } void schedule(proton::duration, proton::void_function0&) OVERRIDE { throw std::logic_error("FIXME"); } atomic_link_namer link_namer; private: template void store(T& v, const T& x) const { lock_guard g(lock_); v = x; } void idle_check(const lock_guard&); void interrupt(); void wait(); const std::string id_; const unique_fd epoll_fd_; const unique_fd interrupt_fd_; mutable std::mutex lock_; proton::connection_options options_; std::map > listeners_; std::map > engines_; std::condition_variable stopped_; bool stopping_; proton::error_condition stop_err_; std::atomic threads_; }; // Base class for pollable file-descriptors. Manages epoll interaction, // subclasses implement virtual work() to do their serialized work. class pollable { public: pollable(int fd, int epoll_fd) : fd_(fd), epoll_fd_(epoll_fd), notified_(false), working_(false) { int flags = check(::fcntl(fd, F_GETFL, 0), "non-blocking"); check(::fcntl(fd, F_SETFL, flags | O_NONBLOCK), "non-blocking"); ::epoll_event ev = {}; ev.data.ptr = this; ::epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, fd_, &ev); } virtual ~pollable() { ::epoll_event ev = {}; ::epoll_ctl(epoll_fd_, EPOLL_CTL_DEL, fd_, &ev); // Ignore errors. } bool do_work(uint32_t events) { { lock_guard g(lock_); if (working_) return true; // Another thread is already working. working_ = true; notified_ = false; } uint32_t new_events = work(events); // Serialized, outside the lock. if (new_events) { lock_guard g(lock_); rearm(notified_ ? EPOLLIN|EPOLLOUT : new_events); } return new_events; } // Called from any thread to wake up the connection handler. void notify() { lock_guard g(lock_); if (!notified_) { notified_ = true; if (!working_) // No worker thread, rearm now. rearm(EPOLLIN|EPOLLOUT); } } protected: // Subclass implements work. // Returns epoll events to re-enable or 0 if finished. virtual uint32_t work(uint32_t events) = 0; const unique_fd fd_; const int epoll_fd_; private: void rearm(uint32_t events) { epoll_event ev; ev.data.ptr = this; ev.events = EPOLLONESHOT | events; check(::epoll_ctl(epoll_fd_, EPOLL_CTL_MOD, fd_, &ev), "re-arm epoll"); working_ = false; } std::mutex lock_; bool notified_; bool working_; }; class epoll_event_loop : public proton::event_loop { public: typedef std::vector > jobs; epoll_event_loop(pollable& p) : pollable_(p), closed_(false) {} bool inject(std::function f) OVERRIDE { // Note this is an unbounded work queue. // A resource-safe implementation should be bounded. lock_guard g(lock_); if (closed_) return false; jobs_.push_back(f); pollable_.notify(); return true; } bool inject(proton::void_function0& f) OVERRIDE { return inject([&f]() { f(); }); } jobs pop_all() { lock_guard g(lock_); return std::move(jobs_); } void close() { lock_guard g(lock_); closed_ = true; } private: std::mutex lock_; pollable& pollable_; jobs jobs_; bool closed_; }; // Handle epoll wakeups for a connection_engine. class pollable_engine : public pollable { public: pollable_engine(epoll_container& c, int fd, int epoll_fd) : pollable(fd, epoll_fd), loop_(new epoll_event_loop(*this)), engine_(c, loop_) { proton::connection conn = engine_.connection(); proton::io::set_link_namer(conn, c.link_namer); } ~pollable_engine() { loop_->close(); // No calls to notify() after this. engine_.dispatch(); // Run any final events. try { write(); } catch(...) {} // Write connection close if we can. for (auto f : loop_->pop_all()) {// Run final queued work for side-effects. try { f(); } catch(...) {} } } uint32_t work(uint32_t events) { try { bool can_read = events & EPOLLIN, can_write = events & EPOLLOUT; do { can_write = can_write && write(); can_read = can_read && read(); for (auto f : loop_->pop_all()) // Run queued work f(); engine_.dispatch(); } while (can_read || can_write); return (engine_.read_buffer().size ? EPOLLIN:0) | (engine_.write_buffer().size ? EPOLLOUT:0); } catch (const std::exception& e) { engine_.disconnected(proton::error_condition("exception", e.what())); } return 0; // Ending } proton::io::connection_engine& engine() { return engine_; } private: static bool try_again(int e) { // These errno values from read or write mean "try again" return (e == EAGAIN || e == EWOULDBLOCK || e == EINTR); } bool write() { proton::io::const_buffer wbuf(engine_.write_buffer()); if (wbuf.size) { ssize_t n = ::write(fd_, wbuf.data, wbuf.size); if (n > 0) { engine_.write_done(n); return true; } else if (n < 0 && !try_again(errno)) { check(n, "write"); } } return false; } bool read() { proton::io::mutable_buffer rbuf(engine_.read_buffer()); if (rbuf.size) { ssize_t n = ::read(fd_, rbuf.data, rbuf.size); if (n > 0) { engine_.read_done(n); return true; } else if (n == 0) engine_.read_close(); else if (!try_again(errno)) check(n, "read"); } return false; } // Lifecycle note: loop_ belongs to the proton::connection, which can live // longer than the engine if the application holds a reference to it, we // disconnect ourselves with loop_->close() in ~connection_engine() epoll_event_loop* loop_; proton::io::connection_engine engine_; }; // A pollable listener fd that creates pollable_engine for incoming connections. class pollable_listener : public pollable { public: pollable_listener( const std::string& addr, proton::listen_handler& l, int epoll_fd, epoll_container& c ) : pollable(socket_listen(addr), epoll_fd), addr_(addr), container_(c), listener_(l) {} uint32_t work(uint32_t events) { if (events & EPOLLRDHUP) { try { listener_.on_close(); } catch (...) {} return 0; } try { int accepted = check(::accept(fd_, NULL, 0), "accept"); container_.add_engine(listener_.on_accept(), accepted, true); return EPOLLIN; } catch (const std::exception& e) { listener_.on_error(e.what()); return 0; } } std::string addr() { return addr_; } private: static int socket_listen(const std::string& addr) { std::string msg = "listen on "+addr; unique_addrinfo ainfo(addr); unique_fd fd(check(::socket(ainfo->ai_family, SOCK_STREAM, 0), msg)); int yes = 1; check(::setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)), msg); check(::bind(fd, ainfo->ai_addr, ainfo->ai_addrlen), msg); check(::listen(fd, 32), msg); return fd.release(); } std::string addr_; std::function factory_; epoll_container& container_; proton::connection_options opts_; proton::listen_handler& listener_; }; epoll_container::epoll_container(const std::string& id) : id_(id), epoll_fd_(check(epoll_create(1), "epoll_create")), interrupt_fd_(check(eventfd(1, 0), "eventfd")), stopping_(false), threads_(0) {} epoll_container::~epoll_container() { try { stop(proton::error_condition("exception", "container shut-down")); wait(); } catch (...) {} } proton::connection epoll_container::add_engine(proton::connection_options opts, int fd, bool server) { lock_guard g(lock_); if (stopping_) throw proton::error("container is stopping"); std::unique_ptr eng(new pollable_engine(*this, fd, epoll_fd_)); if (server) eng->engine().accept(opts); else eng->engine().connect(opts); proton::connection c = eng->engine().connection(); eng->notify(); engines_[eng.get()] = std::move(eng); return c; } void epoll_container::erase(pollable* e) { lock_guard g(lock_); if (!engines_.erase(e)) { pollable_listener* l = dynamic_cast(e); if (l) listeners_.erase(l->addr()); } idle_check(g); } void epoll_container::idle_check(const lock_guard&) { if (stopping_ && engines_.empty() && listeners_.empty()) interrupt(); } proton::returned epoll_container::connect( const std::string& addr, const proton::connection_options& opts) { std::string msg = "connect to "+addr; unique_addrinfo ainfo(addr); unique_fd fd(check(::socket(ainfo->ai_family, SOCK_STREAM, 0), msg)); check(::connect(fd, ainfo->ai_addr, ainfo->ai_addrlen), msg); return make_thread_safe(add_engine(opts, fd.release(), false)); } proton::listener epoll_container::listen(const std::string& addr, proton::listen_handler& lh) { lock_guard g(lock_); if (stopping_) throw proton::error("container is stopping"); auto& l = listeners_[addr]; try { l.reset(new pollable_listener(addr, lh, epoll_fd_, *this)); l->notify(); return proton::listener(*this, addr); } catch (const std::exception& e) { lh.on_error(e.what()); lh.on_close(); throw; } } void epoll_container::stop_listening(const std::string& addr) { lock_guard g(lock_); listeners_.erase(addr); idle_check(g); } void epoll_container::run() { ++threads_; try { epoll_event e; while(true) { check(::epoll_wait(epoll_fd_, &e, 1, -1), "epoll_wait"); pollable* p = reinterpret_cast(e.data.ptr); if (!p) break; // Interrupted if (!p->do_work(e.events)) erase(p); } } catch (const std::exception& e) { stop(proton::error_condition("exception", e.what())); } if (--threads_ == 0) stopped_.notify_all(); } void epoll_container::auto_stop(bool set) { lock_guard g(lock_); stopping_ = set; } void epoll_container::stop(const proton::error_condition& err) { lock_guard g(lock_); stop_err_ = err; interrupt(); } void epoll_container::wait() { std::unique_lock l(lock_); stopped_.wait(l, [this]() { return this->threads_ == 0; } ); for (auto& eng : engines_) eng.second->engine().disconnected(stop_err_); listeners_.clear(); engines_.clear(); } void epoll_container::interrupt() { // Add an always-readable fd with 0 data and no ONESHOT to interrupt all threads. epoll_event ev = {}; ev.events = EPOLLIN; check(epoll_ctl(epoll_fd_, EPOLL_CTL_ADD, interrupt_fd_, &ev), "interrupt"); } } // This is the only public function. std::unique_ptr make_mt_container(const std::string& id) { return std::unique_ptr(new epoll_container(id)); } qpid-proton-0.14.0/examples/cpp/mt/mt_container.hpp0000644000175000017500000000213312770711155021542 0ustar danieldaniel#ifndef MT_MT_CONTROLLER_HPP #define MT_MT_CONTROLLER_HPP /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include // Defined in whichever MT container implementation we are linked with. std::unique_ptr make_mt_container(const std::string& id); #endif // MT_MT_DEFAULT_CONTAINER.HPP qpid-proton-0.14.0/examples/cpp/options.hpp0000644000175000017500000001357712770711155020151 0ustar danieldaniel#ifndef OPTIONS_HPP #define OPTIONS_HPP /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ #include #include #include #include #include namespace example { /** bad_option is thrown for option parsing errors */ struct bad_option : public std::runtime_error { bad_option(const std::string& s) : std::runtime_error(s) {} }; /** Simple command-line option parser for example programs */ class options { public: options(int argc, char const * const * argv) : argc_(argc), argv_(argv), prog_(argv[0]), help_() { size_t slash = prog_.find_last_of("/\\"); if (slash != std::string::npos) prog_ = prog_.substr(slash+1); // Extract prog name from path add_flag(help_, 'h', "help", "Print the help message"); } ~options() { for (opts::iterator i = opts_.begin(); i != opts_.end(); ++i) delete *i; } /** Updates value when parse() is called if option is present with a value. */ template void add_value(T& value, char short_name, const std::string& long_name, const std::string& description, const std::string var) { opts_.push_back(new option_value(value, short_name, long_name, description, var)); } /** Sets flag when parse() is called if option is present. */ void add_flag(bool& flag, char short_name, const std::string& long_name, const std::string& description) { opts_.push_back(new option_flag(flag, short_name, long_name, description)); } /** Parse the command line, return the index of the first non-option argument. *@throws bad_option if there is a parsing error or unknown option. */ int parse() { int arg = 1; for (; arg < argc_ && argv_[arg][0] == '-'; ++arg) { opts::iterator i = opts_.begin(); while (i != opts_.end() && !(*i)->parse(argc_, argv_, arg)) ++i; if (i == opts_.end()) throw bad_option(std::string("unknown option ") + argv_[arg]); } if (help_) throw bad_option(""); return arg; } /** Print a usage message */ friend std::ostream& operator<<(std::ostream& os, const options& op) { os << std::endl << "usage: " << op.prog_ << " [options]" << std::endl; os << std::endl << "options:" << std::endl; for (opts::const_iterator i = op.opts_.begin(); i < op.opts_.end(); ++i) os << **i << std::endl; return os; } private: class option { public: option(char s, const std::string& l, const std::string& d, const std::string v) : short_(std::string("-") + s), long_("--" + l), desc_(d), var_(v) {} virtual ~option() {} virtual bool parse(int argc, char const * const * argv, int &i) = 0; virtual void print_default(std::ostream&) const {} friend std::ostream& operator<<(std::ostream& os, const option& op) { os << " " << op.short_; if (!op.var_.empty()) os << " " << op.var_; os << ", " << op.long_; if (!op.var_.empty()) os << "=" << op.var_; os << std::endl << " " << op.desc_; op.print_default(os); return os; } protected: std::string short_, long_, desc_, var_; }; template class option_value : public option { public: option_value(T& value, char s, const std::string& l, const std::string& d, const std::string& v) : option(s, l, d, v), value_(value) {} bool parse(int argc, char const * const * argv, int &i) { std::string arg(argv[i]); if (arg == short_ || arg == long_) { if (i < argc-1) { set_value(arg, argv[++i]); return true; } else { throw bad_option("missing value for " + arg); } } if (arg.compare(0, long_.size(), long_) == 0 && arg[long_.size()] == '=' ) { set_value(long_, arg.substr(long_.size()+1)); return true; } return false; } virtual void print_default(std::ostream& os) const { os << " (default " << value_ << ")"; } void set_value(const std::string& opt, const std::string& s) { std::istringstream is(s); is >> value_; if (is.fail() || is.bad()) throw bad_option("bad value for " + opt + ": " + s); } private: T& value_; }; class option_flag: public option { public: option_flag(bool& flag, const char s, const std::string& l, const std::string& d) : option(s, l, d, ""), flag_(flag) { flag_ = false; } bool parse(int /*argc*/, char const * const * argv, int &i) { if (argv[i] == short_ || argv[i] == long_) { flag_ = true; return true; } else { return false; } } private: bool &flag_; }; typedef std::vector opts; int argc_; char const * const * argv_; std::string prog_; opts opts_; bool help_; }; } #endif // OPTIONS_HPP qpid-proton-0.14.0/examples/cpp/queue_browser.cpp0000644000175000017500000000373712770711155021335 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" using proton::source_options; class browser : public proton::messaging_handler { private: proton::url url; public: browser(const std::string& u) : url(u) {} void on_container_start(proton::container &c) OVERRIDE { proton::connection conn = c.connect(url); source_options browsing = source_options().distribution_mode(proton::source::COPY); conn.open_receiver(url.path(), proton::receiver_options().source(browsing)); } void on_message(proton::delivery &, proton::message &m) OVERRIDE { std::cout << m.body() << std::endl; } }; int main(int argc, char **argv) { try { std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples"; browser b(url); proton::default_container(b).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/scheduled_send.cpp0000644000175000017500000000661412770711155021414 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include "fake_cpp11.hpp" // Send messages at a constant rate one per interval. cancel after a timeout. class scheduled_sender : public proton::messaging_handler { private: std::string url; proton::sender sender; proton::duration interval, timeout; bool ready, canceled; public: scheduled_sender(const std::string &s, double d, double t) : url(s), interval(int(d*proton::duration::SECOND.milliseconds())), // Send interval. timeout(int(t*proton::duration::SECOND.milliseconds())), // Cancel after timeout. ready(true), // Ready to send. canceled(false) // Canceled. {} void on_container_start(proton::container &c) OVERRIDE { sender = c.open_sender(url); // Call this->cancel after timeout. c.schedule(timeout, [this]() { this->cancel(); }); // Start regular ticks every interval. c.schedule(interval, [this]() { this->tick(); }); } void cancel() { canceled = true; sender.connection().close(); } void tick() { // Schedule the next tick unless we have been cancelled. if (!canceled) sender.container().schedule(interval, [this]() { this->tick(); }); if (sender.credit() > 0) // Only send if we have credit send(); else ready = true; // Set the ready flag, send as soon as we get credit. } void on_sendable(proton::sender &) OVERRIDE { if (ready) // We have been ticked since the last send. send(); } void send() { std::cout << "send" << std::endl; sender.send(proton::message("ping")); ready = false; } }; int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); double interval = 1.0; double timeout = 5.0; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); opts.add_value(interval, 'i', "interval", "send a message every INTERVAL seconds", "INTERVAL"); opts.add_value(timeout, 't', "timeout", "stop after T seconds", "T"); try { opts.parse(); scheduled_sender h(address, interval, timeout); proton::default_container(h).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/scheduled_send_03.cpp0000644000175000017500000000747612770711155021725 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include "fake_cpp11.hpp" // Send messages at a constant rate one per interval. cancel after a timeout. // This example uses only C++03 features. class scheduled_sender : public proton::messaging_handler { private: std::string url; proton::sender sender; proton::duration interval, timeout; bool ready, canceled; struct tick_fn : public proton::void_function0 { scheduled_sender& parent; tick_fn(scheduled_sender& ss) : parent(ss) {} void operator()() { parent.tick(); } }; struct cancel_fn : public proton::void_function0 { scheduled_sender& parent; cancel_fn(scheduled_sender& ss) : parent(ss) {} void operator()() { parent.cancel(); } }; tick_fn do_tick; cancel_fn do_cancel; public: scheduled_sender(const std::string &s, double d, double t) : url(s), interval(int(d*proton::duration::SECOND.milliseconds())), // Send interval. timeout(int(t*proton::duration::SECOND.milliseconds())), // Cancel after timeout. ready(true), // Ready to send. canceled(false), // Canceled. do_tick(*this), do_cancel(*this) {} void on_container_start(proton::container &c) OVERRIDE { sender = c.open_sender(url); c.schedule(timeout, do_cancel); // Call this->cancel after timeout. c.schedule(interval, do_tick); // Start regular ticks every interval. } void cancel() { canceled = true; sender.connection().close(); } void tick() { if (!canceled) { sender.container().schedule(interval, do_tick); // Next tick if (sender.credit() > 0) // Only send if we have credit send(); else ready = true; // Set the ready flag, send as soon as we get credit. } } void on_sendable(proton::sender &) OVERRIDE { if (ready) // We have been ticked since the last send. send(); } void send() { std::cout << "send" << std::endl; sender.send(proton::message("ping")); ready = false; } }; int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); double interval = 1.0; double timeout = 5.0; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); opts.add_value(interval, 'i', "interval", "send a message every INTERVAL seconds", "INTERVAL"); opts.add_value(timeout, 't', "timeout", "stop after T seconds", "T"); try { opts.parse(); scheduled_sender h(address, interval, timeout); proton::default_container(h).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/selected_recv.cpp0000644000175000017500000000541012770711155021243 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include #include #include "fake_cpp11.hpp" namespace { // Example custom function to configure an AMQP filter, // specifically an APACHE.ORG:SELECTOR // (http://www.amqp.org/specification/1.0/filters) void set_filter(proton::source_options &opts, const std::string& selector_str) { proton::source::filter_map map; proton::symbol filter_key("selector"); proton::value filter_value; // The value is a specific AMQP "described type": binary string with symbolic descriptor proton::codec::encoder enc(filter_value); enc << proton::codec::start::described() << proton::symbol("apache.org:selector-filter:string") << proton::binary(selector_str) << proton::codec::finish(); // In our case, the map has this one element map.put(filter_key, filter_value); opts.filters(map); } } class selected_recv : public proton::messaging_handler { private: proton::url url; public: selected_recv(const std::string& u) : url(u) {} void on_container_start(proton::container &c) OVERRIDE { proton::source_options opts; set_filter(opts, "colour = 'green'"); proton::connection conn = c.connect(url); conn.open_receiver(url.path(), proton::receiver_options().source(opts)); } void on_message(proton::delivery &, proton::message &m) OVERRIDE { std::cout << m.body() << std::endl; } }; int main(int argc, char **argv) { try { std::string url = argc > 1 ? argv[1] : "127.0.0.1:5672/examples"; selected_recv recv(url); proton::default_container(recv).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/server.cpp0000644000175000017500000000546612770711155017755 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" class server : public proton::messaging_handler { private: typedef std::map sender_map; proton::url url; proton::connection connection; sender_map senders; public: server(const std::string &u) : url(u) {} void on_container_start(proton::container &c) OVERRIDE { connection = c.connect(url); connection.open_receiver(url.path()); std::cout << "server connected to " << url << std::endl; } std::string to_upper(const std::string &s) { std::string uc(s); size_t l = uc.size(); for (size_t i=0; i(std::toupper(uc[i])); return uc; } void on_message(proton::delivery &, proton::message &m) OVERRIDE { std::cout << "Received " << m.body() << std::endl; std::string reply_to = m.reply_to(); proton::message reply; reply.to(reply_to); reply.body(to_upper(proton::get(m.body()))); reply.correlation_id(m.correlation_id()); if (!senders[reply_to]) { senders[reply_to] = connection.open_sender(reply_to); } senders[reply_to].send(reply); } }; int main(int argc, char **argv) { std::string address("amqp://0.0.0.0:5672/examples"); example::options opts(argc, argv); opts.add_value(address, 'a', "address", "listen on URL", "URL"); try { opts.parse(); server srv(address); proton::default_container(srv).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/server_direct.cpp0000644000175000017500000000656612770711155021311 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" class server : public proton::messaging_handler { private: typedef std::map sender_map; std::string url; sender_map senders; int address_counter; public: server(const std::string &u) : url(u), address_counter(0) {} void on_container_start(proton::container &c) OVERRIDE { c.listen(url); std::cout << "server listening on " << url << std::endl; } std::string to_upper(const std::string &s) { std::string uc(s); size_t l = uc.size(); for (size_t i=0; i(std::toupper(uc[i])); return uc; } std::string generate_address() { std::ostringstream addr; addr << "server" << address_counter++; return addr.str(); } void on_sender_open(proton::sender &sender) OVERRIDE { if (sender.source().dynamic()) { std::string addr = generate_address(); sender.open(proton::sender_options().source(proton::source_options().address(addr))); senders[addr] = sender; } } void on_message(proton::delivery &, proton::message &m) OVERRIDE { std::cout << "Received " << m.body() << std::endl; std::string reply_to = m.reply_to(); sender_map::iterator it = senders.find(reply_to); if (it == senders.end()) { std::cout << "No link for reply_to: " << reply_to << std::endl; } else { proton::sender sender = it->second; proton::message reply; reply.to(reply_to); reply.body(to_upper(proton::get(m.body()))); reply.correlation_id(m.correlation_id()); sender.send(reply); } } }; int main(int argc, char **argv) { std::string address("amqp://127.0.0.1:5672/examples"); example::options opts(argc, argv); opts.add_value(address, 'a', "address", "listen on URL", "URL"); try { opts.parse(); server srv(address); proton::default_container(srv).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/service_bus.cpp0000644000175000017500000003134012770711155020746 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /* * Service Bus example. * * This is an example of using "Service Bus sessions" (not the same thing as an * AMQP session) to selectively retrieve messages from a queue. The queue must * be configured within Service Bus to support sessions. Service Bus uses the * AMQP group_id message property to associate messages with a particular * Service Bus session. It uses AMQP filters to specify which session is * associated with a receiver. * * The mechanics for sending and receiving to other types of service bus queue * are broadly the same, as long as the step using the * receiver.source().filters() is omitted. * * Other Service Bus notes: There is no drain support, hence the need to to use * timeouts in this example to detect the end of the message stream. There is * no browse support when setting the AMQP link distribution mode to COPY. * Service Bus claims to support browsing, but it is unclear how to manage that * with an AMQP client. Maximum message sizes (for body and headers) vary * between queue types and fee tier ranging from 64KB to 1MB. Due to the * distributed nature of Service Bus, queues do not automatically preserve FIFO * order of messages unless the user takes steps to force the message stream to * a single partition of the queue or creates the queue with partitioning disabled. * * This example shows use of the simpler SAS (Shared Access Signature) * authentication scheme where the credentials are supplied on the connection. * Service Bus does not actually check these credentials when setting up the * connection, it merely caches the SAS key and policy (AKA key name) for later * access authorization when creating senders and receivers. There is a second * authentication scheme that allows for multiple tokens and even updating them * within a long-lived connection which uses special management request-response * queues in Service Bus. The format of this exchange may be documented * somewhere but is also available by working through the CbsAsyncExample.cs * program in the Amqp.Net Lite project. * * The sample output for this program is: sent message: message 0 in service bus session "red" sent message: message 1 in service bus session "green" sent message: message 2 in service bus session "blue" sent message: message 3 in service bus session "red" sent message: message 4 in service bus session "black" sent message: message 5 in service bus session "blue" sent message: message 6 in service bus session "yellow" receiving messages with session identifier "green" from queue ses_q1 received message: message 1 in service bus session "green" receiving messages with session identifier "red" from queue ses_q1 received message: message 0 in service bus session "red" received message: message 3 in service bus session "red" receiving messages with session identifier "blue" from queue ses_q1 received message: message 2 in service bus session "blue" received message: message 5 in service bus session "blue" receiving messages with session identifier "black" from queue ses_q1 received message: message 4 in service bus session "black" receiving messages with session identifier "yellow" from queue ses_q1 received message: message 6 in service bus session "yellow" Done. No more messages. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" using proton::source_options; using proton::connection_options; using proton::sender_options; using proton::receiver_options; void do_next_sequence(); namespace { void check_arg(const std::string &value, const std::string &name) { if (value.empty()) throw std::runtime_error("missing argument for \"" + name + "\""); } } /// Connect to Service Bus queue and retrieve messages in a particular session. class session_receiver : public proton::messaging_handler { private: const std::string &connection_url; const std::string &entity; proton::value session_identifier; // AMQP null type by default, matches any Service Bus sequence identifier int message_count; bool closed; proton::duration read_timeout; proton::timestamp last_read; proton::container *container; proton::receiver receiver; struct process_timeout_fn : public proton::void_function0 { session_receiver& parent; process_timeout_fn(session_receiver& sr) : parent(sr) {} void operator()() { parent.process_timeout(); } }; process_timeout_fn do_process_timeout; public: session_receiver(const std::string &c, const std::string &e, const char *sid) : connection_url(c), entity(e), message_count(0), closed(false), read_timeout(5000), last_read(0), container(0), do_process_timeout(*this) { if (sid) session_identifier = std::string(sid); // session_identifier is now either empty/null or an AMQP string type. // If null, Service Bus will pick the first available message and create // a filter at its end with that message's session identifier. // Technically, an AMQP string is not a valid filter-set value unless it // is annotated as an AMQP described type, so this may change. } void run (proton::container &c) { message_count = 0; closed = false; c.connect(connection_url, connection_options().handler(*this)); container = &c; } void on_connection_open(proton::connection &connection) OVERRIDE { proton::source::filter_map sb_filter_map; proton::symbol key("com.microsoft:session-filter"); sb_filter_map.put(key, session_identifier); receiver = connection.open_receiver(entity, receiver_options().source(source_options().filters(sb_filter_map))); // Start timeout processing here. If Service Bus has no pending // messages, it may defer completing the receiver open until a message // becomes available (e.g. to be able to set the actual session // identifier if none was specified). last_read = proton::timestamp::now(); // Call this->process_timeout after read_timeout. container->schedule(read_timeout, do_process_timeout); } void on_receiver_open(proton::receiver &r) OVERRIDE { if (closed) return; // PROTON-1264 proton::value actual_session_id = r.source().filters().get("com.microsoft:session-filter"); std::cout << "receiving messages with session identifier \"" << actual_session_id << "\" from queue " << entity << std::endl; last_read = proton::timestamp::now(); } void on_message(proton::delivery &, proton::message &m) OVERRIDE { message_count++; std::cout << " received message: " << m.body() << std::endl; last_read = proton::timestamp::now(); } void process_timeout() { proton::timestamp deadline = last_read + read_timeout; proton::timestamp now = proton::timestamp::now(); if (now >= deadline) { receiver.close(); closed = true; receiver.connection().close(); if (message_count) do_next_sequence(); else std::cout << "Done. No more messages." << std::endl; } else { proton::duration next = deadline - now; container->schedule(next, do_process_timeout); } } }; /// Connect to Service Bus queue and send messages divided into different sessions. class session_sender : public proton::messaging_handler { private: const std::string &connection_url; const std::string &entity; int msg_count; int total; int accepts; public: session_sender(const std::string &c, const std::string &e) : connection_url(c), entity(e), msg_count(0), total(7), accepts(0) {} void run(proton::container &c) { c.open_sender(connection_url + "/" + entity, sender_options(), connection_options().handler(*this)); } void send_remaining_messages(proton::sender &s) { std::string gid; for (; msg_count < total && s.credit() > 0; msg_count++) { switch (msg_count) { case 0: gid = "red"; break; case 1: gid = "green"; break; case 2: gid = "blue"; break; case 3: gid = "red"; break; case 4: gid = "black"; break; case 5: gid = "blue"; break; case 6: gid = "yellow"; break; } std::ostringstream mbody; mbody << "message " << msg_count << " in service bus session \"" << gid << "\""; proton::message m(mbody.str()); m.group_id(gid); // Service Bus uses the group_id property to as the session identifier. s.send(m); std::cout << " sent message: " << m.body() << std::endl; } } void on_sendable(proton::sender &s) OVERRIDE { send_remaining_messages(s); } void on_tracker_accept(proton::tracker &t) OVERRIDE { accepts++; if (accepts == total) { // upload complete t.sender().close(); t.sender().connection().close(); do_next_sequence(); } } }; /// Orchestrate the sequential actions of sending and receiving session-based messages. class sequence : public proton::messaging_handler { private: proton::container *container; int sequence_no; session_sender snd; session_receiver rcv_red, rcv_green, rcv_null; public: static sequence *the_sequence; sequence (const std::string &c, const std::string &e) : sequence_no(0), snd(c, e), rcv_red(c, e, "red"), rcv_green(c, e, "green"), rcv_null(c, e, NULL) { the_sequence = this; } void on_container_start(proton::container &c) OVERRIDE { container = &c; next_sequence(); } void next_sequence() { switch (sequence_no++) { // run these in order exactly once case 0: snd.run(*container); break; case 1: rcv_green.run(*container); break; case 2: rcv_red.run(*container); break; // Run this until the receiver decides there is no messages left to sequence through default: rcv_null.run(*container); break; } } }; sequence *sequence::the_sequence = NULL; void do_next_sequence() { sequence::the_sequence->next_sequence(); } int main(int argc, char **argv) { std::string sb_namespace; // i.e. "foo.servicebus.windows.net" // Make sure the next two are urlencoded for Proton std::string sb_key_name; // shared access key name for entity (AKA "Policy Name") std::string sb_key; // shared access key std::string sb_entity; // AKA the service bus queue. Must enable // sessions on it for this example. example::options opts(argc, argv); opts.add_value(sb_namespace, 'n', "namespace", "Service Bus full namespace", "NAMESPACE"); opts.add_value(sb_key_name, 'p', "policy", "policy name that specifies access rights (key name)", "POLICY"); opts.add_value(sb_key, 'k', "key", "secret key for the policy", "key"); opts.add_value(sb_entity, 'e', "entity", "entity path (queue name)", "ENTITY"); try { opts.parse(); check_arg(sb_namespace, "namespace"); check_arg(sb_key_name, "policy"); check_arg(sb_key, "key"); check_arg(sb_entity, "entity"); std::string connection_string("amqps://" + sb_key_name + ":" + sb_key + "@" + sb_namespace); sequence seq(connection_string, sb_entity); proton::default_container(seq).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/simple_recv.cpp0000644000175000017500000000622112770711155020745 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" class simple_recv : public proton::messaging_handler { private: std::string url; std::string user; std::string password; proton::receiver receiver; uint64_t expected; uint64_t received; public: simple_recv(const std::string &s, const std::string &u, const std::string &p, int c) : url(s), user(u), password(p), expected(c), received(0) {} void on_container_start(proton::container &c) OVERRIDE { proton::connection_options co; if (!user.empty()) co.user(user); if (!password.empty()) co.password(password); receiver = c.open_receiver(url, co); std::cout << "simple_recv listening on " << url << std::endl; } void on_message(proton::delivery &d, proton::message &msg) OVERRIDE { if (proton::get(msg.id()) < received) { return; // Ignore duplicate } if (expected == 0 || received < expected) { std::cout << msg.body() << std::endl; received++; if (received == expected) { d.receiver().close(); d.connection().close(); } } } }; int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); std::string user; std::string password; int message_count = 100; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect to and receive from URL", "URL"); opts.add_value(message_count, 'm', "messages", "receive COUNT messages", "COUNT"); opts.add_value(user, 'u', "user", "authenticate as USER", "USER"); opts.add_value(password, 'p', "password", "authenticate with PASSWORD", "PASSWORD"); try { opts.parse(); simple_recv recv(address, user, password, message_count); proton::default_container(recv).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/simple_send.cpp0000644000175000017500000000630412770711155020741 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include "fake_cpp11.hpp" class simple_send : public proton::messaging_handler { private: std::string url; std::string user; std::string password; proton::sender sender; int sent; int confirmed; int total; public: simple_send(const std::string &s, const std::string &u, const std::string &p, int c) : url(s), user(u), password(p), sent(0), confirmed(0), total(c) {} void on_container_start(proton::container &c) OVERRIDE { proton::connection_options co; if (!user.empty()) co.user(user); if (!password.empty()) co.password(password); sender = c.open_sender(url, co); } void on_sendable(proton::sender &s) OVERRIDE { while (s.credit() && sent < total) { proton::message msg; std::map m; m["sequence"] = sent + 1; msg.id(sent + 1); msg.body(m); s.send(msg); sent++; } } void on_tracker_accept(proton::tracker &t) OVERRIDE { confirmed++; if (confirmed == total) { std::cout << "all messages confirmed" << std::endl; t.connection().close(); } } void on_transport_close(proton::transport &) OVERRIDE { sent = confirmed; } }; int main(int argc, char **argv) { std::string address("127.0.0.1:5672/examples"); std::string user; std::string password; int message_count = 100; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); opts.add_value(message_count, 'm', "messages", "send COUNT messages", "COUNT"); opts.add_value(user, 'u', "user", "authenticate as USER", "USER"); opts.add_value(password, 'p', "password", "authenticate with PASSWORD", "PASSWORD"); try { opts.parse(); simple_send send(address, user, password, message_count); proton::default_container(send).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/examples/cpp/ssl.cpp0000644000175000017500000002140212770711155017234 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" using proton::connection_options; using proton::ssl_client_options; using proton::ssl_server_options; using proton::ssl_certificate; // Helper functions defined below. bool using_OpenSSL(); std::string platform_CA(const std::string &base_name); ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd); std::string find_CN(const std::string &); namespace { std::string verify_full("full"); // Normal verification std::string verify_noname("noname"); // Skip matching host name against the certificate std::string verify_fail("fail"); // Force name mismatch failure std::string verify(verify_full); // Default for example std::string cert_directory; class example_cert_error : public std::runtime_error { public: explicit example_cert_error(const std::string& s) : std::runtime_error(s) {} }; } struct server_handler : public proton::messaging_handler { std::string url; void on_connection_open(proton::connection &c) OVERRIDE { std::cout << "Inbound server connection connected via SSL. Protocol: " << c.transport().ssl().protocol() << std::endl; c.container().stop_listening(url); // Just expecting the one connection. } void on_transport_error(proton::transport &t) OVERRIDE { t.connection().container().stop_listening(url); } void on_message(proton::delivery &, proton::message &m) OVERRIDE { std::cout << m.body() << std::endl; } }; class hello_world_direct : public proton::messaging_handler { private: std::string url; server_handler s_handler; public: hello_world_direct(const std::string& u) : url(u) {} void on_container_start(proton::container &c) OVERRIDE { // Configure listener. Details vary by platform. ssl_certificate server_cert = platform_certificate("tserver", "tserverpw"); ssl_server_options ssl_srv(server_cert); connection_options server_opts; server_opts.ssl_server_options(ssl_srv).handler(s_handler); c.server_connection_options(server_opts); // Configure client with a Certificate Authority database // populated with the server's self signed certificate. connection_options client_opts; if (verify == verify_full) { ssl_client_options ssl_cli(platform_CA("tserver")); client_opts.ssl_client_options(ssl_cli); // The next line is optional in normal use. Since the // example uses IP addresses in the connection string, use // the virtual_host option to set the server host name // used for certificate verification: client_opts.virtual_host("test_server"); } else if (verify == verify_noname) { // Downgrade the verification from VERIFY_PEER_NAME to VERIFY_PEER. ssl_client_options ssl_cli(platform_CA("tserver"), proton::ssl::VERIFY_PEER); client_opts.ssl_client_options(ssl_cli); } else if (verify == verify_fail) { ssl_client_options ssl_cli(platform_CA("tserver")); client_opts.ssl_client_options(ssl_cli); client_opts.virtual_host("wrong_name_for_server"); // Pick any name that doesn't match. } else throw std::logic_error("bad verify mode: " + verify); c.client_connection_options(client_opts); s_handler.url = url; c.listen(url); c.open_sender(url); } void on_connection_open(proton::connection &c) OVERRIDE { std::string subject = c.transport().ssl().remote_subject(); std::cout << "Outgoing client connection connected via SSL. Server certificate identity " << find_CN(subject) << std::endl; } void on_transport_error(proton::transport &t) OVERRIDE { std::string err = t.error().what(); if (err.find("certificate")) throw example_cert_error(err); } void on_sendable(proton::sender &s) OVERRIDE { proton::message m; m.body("Hello World!"); s.send(m); s.close(); } void on_tracker_accept(proton::tracker &t) OVERRIDE { // All done. t.connection().close(); } }; int main(int argc, char **argv) { // Pick an "unusual" port since we are going to be talking to // ourselves, not a broker. // Note the use of "amqps" as the URL scheme to denote a TLS/SSL connection. std::string address("amqps://127.0.0.1:8888/examples"); example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); opts.add_value(cert_directory, 'c', "cert_directory", "directory containing SSL certificates and private key information", "CERTDIR"); opts.add_value(verify, 'v', "verify", "verify type: \"minimum\", \"full\", \"fail\"", "VERIFY"); try { opts.parse(); size_t sz = cert_directory.size(); if (sz && cert_directory[sz -1] != '/') cert_directory.append("/"); else cert_directory = "ssl_certs/"; if (verify != verify_noname && verify != verify_full && verify != verify_fail) throw std::runtime_error("bad verify argument: " + verify); hello_world_direct hwd(address); proton::default_container(hwd).run(); return 0; } catch (const example_cert_error& ce) { if (verify == verify_fail) { std::cout << "Expected failure of connection with wrong peer name: " << ce.what() << std::endl; return 0; } std::cerr << "unexpected internal certificate failure: " << ce.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } bool using_OpenSSL() { // Current defaults. #if defined(WIN32) return false; #else return true; #endif } ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd) { if (using_OpenSSL()) { // The first argument will be the name of the file containing the public certificate, the // second argument will be the name of the file containing the private key. return ssl_certificate(cert_directory + base_name + "-certificate.pem", cert_directory + base_name + "-private-key.pem", passwd); } else { // Windows SChannel // The first argument will be the database or store that contains one or more complete certificates // (public and private data). The second will be an optional name of the certificate in the store // (not used in this example with one certificate per store). return ssl_certificate(cert_directory + base_name + "-full.p12", "", passwd); } } std::string platform_CA(const std::string &base_name) { if (using_OpenSSL()) { // In this simple example with self-signed certificates, the peer's certificate is the CA database. return cert_directory + base_name + "-certificate.pem"; } else { // Windows SChannel. Use a pkcs#12 file with just the peer's public certificate information. return cert_directory + base_name + "-certificate.p12"; } } std::string find_CN(const std::string &subject) { // The subject string is returned with different whitespace and component ordering between platforms. // Here we just return the common name by searching for "CN=...." in the subject, knowing that // the test certificates do not contain any escaped characters. size_t pos = subject.find("CN="); if (pos == std::string::npos) throw std::runtime_error("No common name in certificate subject"); std::string cn = subject.substr(pos); pos = cn.find(','); return pos == std::string::npos ? cn : cn.substr(0, pos); } qpid-proton-0.14.0/examples/cpp/ssl_certs/0000755000175000017500000000000012770711155017731 5ustar danieldanielqpid-proton-0.14.0/examples/cpp/ssl_certs/README.txt0000644000175000017500000000165012770711155021431 0ustar danieldanielThis directory contains basic self signed test certificates for use by proton examples. The ".pem" files are in the format expected by proton implementations using OpenSSL. The ".p12" file are for Windows implementations using SChannel. The commands used to generate the certificates follow. make_pn_cert() { name=$1 subject=$2 passwd=$3 # create the pem files openssl req -newkey rsa:2048 -keyout $name-private-key.pem -out $name-certificate.pem -subj $subject -passout pass:$passwd -x509 -days 3650 # create the p12 files openssl pkcs12 -export -out $name-full.p12 -passin pass:$passwd -passout pass:$passwd -inkey $name-private-key.pem -in $name-certificate.pem -name $name openssl pkcs12 -export -out $name-certificate.p12 -in $name-certificate.pem -name $name -nokeys -passout pass: } make_pn_cert tserver /CN=test_server/OU=proton_test tserverpw make_pn_cert tclient /CN=test_client/OU=proton_test tclientpw qpid-proton-0.14.0/examples/cpp/ssl_certs/tclient-certificate.p120000644000175000017500000000201012770711155024170 0ustar danieldaniel0‚0‚Ê *†H†÷  ‚»‚·0‚³0‚¯ *†H†÷  ‚ 0‚œ0‚• *†H†÷ 0 *†H†÷  0Ÿ;x­€€‚hZ ¹9VegrY›Yx镸ó÷†7«MgO‚P­l!!f‹& ¥¼>²„±eIŒ¸Å÷ÇU_Ãàp?ÔK3b=sXšã¼Gæž/fsÙ z Æbž-R1J21µ ŸçTY°¬ŸÝÙùY—«Ò&®/ê÷ÛÃPà ŸÎ¹W «×¡~‰R˜_Ðî—vgaõ]+²nSqTó-¹‡Å?ß¾¥ò þ± øÖa(…q¼?À*à®yO R'Ü‹lFìaØVPÇ1ûÅì­%Jj» È&·ñyFï÷ËÓ<€ïH;ùTDT,©FBRcâ)^’¤iÙŸ»¾ï,¯ M’ß,ßÒÎÉNrŒÄ7S'>¶‡¾ñòð~ŒD?_ц"ŒÓO¶ØBL¡3°ñq⣑Æ)ÿ»1ç^}½ë>åM·/ÃיzÓéE´càCüßÑ­ðשj¼ÆØõª,¼ÈÄÆ.¹BI4݋ͥ+­ª‘§bà.•œÛǵ»<‰þZl£©X®öpñ€ÍÀE³¡>eóŒÂÜ13lrDoú Q_R®',*üs¨ã[á+ÚcÝqà{óT›þ˱åÝ ‚É(,:ÕL–0i˜ÕXr§Ù.ãÉ= Æ/RÒlïñõñá0`.¾TŽ8:dUö4š b„Xš\n®@’2è†ôÎS)PïŸø¢åhÜ:Âo“sîa›Þ^[¿Áä´|¼êSe÷L­jËèFÚZ%—vZï.!—6"Kê…Õüêœà]óñ]N„©P×Jß¡Ø ?èò,~¯OÑuØ*Ï «ìzêI ŠDöâ!ÃP—È>ßQñ¦Î™µ0ÝÙ‡éJm[„_ç-óbu„®}Û“Žíû}€GDÌÿ¾‰ÜùÈ |©iÙúœòº`¾à¢o^ÁŽÓds@ä÷]I@hO9CÈ·S›¸(Ä€»ÞU¤WÞ3¦dªK,ŠÞ\+D¤7ÍXÈx¬… ½ÿX؉0ôßÁ%™t¯kÇúW¢G›ÿq2ÂC|¸Ý€þŸâåÀüÑÐbMÈzá·$ú’¡×œ¢¯“Îq  [{A* Ë¶Ù³á;!ÂÍœ®nÑð(Cæô;w Àî"010!0 +Ø*×[. Æ•c¸³ŽíŸֱ‹ L8SÉ?ÂÔ'ç®YºG´]ØJd³Ð*b§¿Ì /I µŒv¯ø*§±ªHVnâ·bŸiÃU‹iRLÚ'ŠéÌУS¯¦²†î{Øñ²èÑ~ÇG8 }Ú¨]|ƒ«Ýi|)ä‘ý8žVMÀždÓýN‚ïÛÛžÕ…»{µ9ºßÎoS}¹ÎÔä?²c½1>67)òÁ:ˆ:ïÁÈ/é-_/‡öšˆF 7Š›Jmý/ïßÅ«w¦¼O¡`aW NLJU¡ËÅŸõ=îáÃqJíˆYT)µ‡sõ¯1ã–Dg“ZÇÞR4’/_rs#{0XØG¿—þfËÊSäGÝ„<ÿxe«Ä8ô~Ú :_ðÓ¼`ÿÛ©Kÿ~ Æø-snºØkºÙ[kÐIÔ hû9f“Ÿl9„BˆAU¸¼›ºAoIиNƒZvbzÈ.h„FÑËý«ÓÇù?–2±šªéØ0Ð>;9ëHE%8‹À“ÕÞúÓÕ1bBZ!¢Cx®y&þVŠ4?½]yf%Àå‚l4 *ÔÚÓ)¹ŸÎXr½>’ ›ÛL„“ <9ZŠðÜÿ Š(…íFšM´±ìmäZ½0LŒ‹D¢U«M¸C§Aý‘y!C¡1!ëK6î+—Ñ]XK¦Ì§-v,f<úkÐà>{¶çÄ!¹ùù¦2“Ä`÷EeÜOÐÀÎËA³è|$ºÙÂSéiMöª‘e]¦HÆ,s3%¨{öÜ1Cþ̧òDJ9õÀàÐ5:ý%BÁg2]‘Ý <;‹š…Eòš7ëÖ±·ÊÈŠÚê*)Êó'››87êÝ–ÒŽáaòš>†ÌuÙÓ5½¬Ϩ†‘SµC^t=gÞÿœ"Ê(gêú¶!£çôR_¾àM\芙KXlFÚ^$‹¿kl pSMdMÔ×?yUêÈÓ1 䌓"ÃòߦÖËÑœN:\5§õDﻼhD$Éý¨j ~úùlL ^eÄœ d´Àæíf(€7ÿ½²Aº\²ÍÖ˜˜'i.½Zxßø"¾ ¹ÀO¢øml0³É¡y#U·<ä¸Ö ›Y^.Æi6Ìnì,`lÍ‚tç÷~­æn®ì¢— F¥ö@œ‘##*+þ vsÓ qÌ6QoâÆ ª0€qHP³£VFe|Á¸ Ó_D £0‚` *†H†÷  ‚Q‚M0‚I0‚E *†H†÷   ‚î0‚ê0 *†H†÷  0MÌ©ŽéË‚È×süUsÉ‹«j¹T6?gb'dʸ܉³ö_frZ‰ÂJ‚Lg‹¨®}R$Z1 °ç2Ô‚õX“5‘d?âåž''µÛàÉÃ3¯¿ýñK-)@ `$  ÿw?H$¤vÞU<}»è£\Öï ÌQ OJ˜`¡Á7㥒L¼á¥L€Êy:yVTF*ñqSßšm£¤¼d+ÄÞ%3œ½ò‚cáÌŸ&l1ª0ï~ÞÁ€'¡¢ç‹WŸª\=ñ…CH¾ë `üäèÜPAW'Iþ™Hˆ: òRÒia­ó,þW^ýžž¾ÆŒ²ɧ‚ð #|ç?{DGh‚ßüÉ',/£ßå±;.ÖÛ}°\›"h­x™·Ošø€d@;Èù*Íffm  ­ñ™ÐÑ€&.¯ ed»µ HŸ7–.å'‹”)¤âR͹kpi‹ÐZ$Îr ÷W"E›N~¯ÓÊ@,R{Óá;-‚̼häÄÌÉ#=¨§äžŸI@Ñ‚·FÁ{Â">•³˜xxg«²ØHBŸ&ñ¡sâ^&¹Z¼Çõ‹}Œ/ÉyÍ5{rp{ ƃH¡³»†’?§$6íHàQ¼foð Àñ² lfôYí´¾SÆe…Ï=‡H=Èô}¬¨ƒãØ<: µ¹™ï:Yk¥ÕT®ý*áˆI’apØuOp|X*o^ûwK­‰{ôL?Ëß±ùEz#ÉD™§é³Çò)lĺѓdW0æá(®–$|·Ñp˜lú^$µ©5ØÉÊ'í» Ø>ŒÃì`u:òàšwò¸“[o™ áÛtMœÐpíJ§è/ üI4Iè’ý(#2æ|‘vÄE†6¡àmÿûܦ\tñ ÝyÎñ"6' ak‚Áb‚¸6nþÿ!IÚžl¸&-¼Úg‡—Üf½ ÀwƒfÊl7ãn}oìy‹*}š´½G'©±k¸½]P áªÓ ë÷GÁ’ù#güfoÑÿý|ÃÕâ÷ì"MýøÞÝRtoR++œzõUÓÞ$š!hŸv}z'妡­%”—Oµ”d*˜V­‰¼ýAËígôBW$´²7~ŽõO÷Œ¼ÂùúŽž¼qÞF2‚­rm€Q¢ÊprI m^íEaD¢'ßà(¼v=퇋òøßö¼…­âXäb¹F CôÛÏçr@ ë —\GÝf\å YGÿÊ#\6³²“êx¢V‰©´êô6Òå_&?”“4¿w?×Ü–l=—ì¨2yáj·3é”}Sï«íeƒ’dÑ_d1=½ë–âûŒWÝL`Õdc„ÕÉŽÜ݇CƒœÇ<1#–аèsJü}÷Ò¬ W;¶ŒX×ô³oÑÚOy Ä/ÿY­ôž²ð†.Í€PâŒä–íŠn³Ïg¶Öž¤®(#ó¿„&¨hÛ,†ö„ÅCç3H1D0 *†H†÷  1tclient0# *†H†÷  1ÅHEFz8íÑ&Ê YÁµÀÿ ‘ÏúÌ &ÿ°ýÍ&èƒÿ7 y|a»ÉÙŠ„_Ÿ~¤äçVñØý—p®gp#ˆZ<‘:‚ÎKZ]í À,P½k~;3#A3¬I›¿€ÉxëÞûò(–;¸¬Ø-‡ŒI‹é’Z·1=Ê4Ehw<ÿpšE¯ οV¼w‹!ÓŒëÞƒ!ÁD šîáM˜%µF^pôD"û…†l6Ô‚,})5ò© ³TÌžë*ÔÊ,›Ÿs? òÕQpÈoñR$f®šþâ¦åªætÎ'Îé¿NóîÛ¿±P9”!VÓMƒÖ6OG݇h‹†€¶ò(õ¸”Iît±Õ\BÌ-»Ê”$„ÇS²×8ºÅ ¹qÍÿÇU¤RÖqRAó/ZvAõ~ÂõjûvÎe&ׂA™­ëªrOU LBHŠõá^³)ˆû"Ï”OD*£l,v!Mý"·ÍàrÐ&œ˜³žý©GçON-Ρ]͸.¥>‰RE¡°ÌVÊ›‹)žs†Ð(æsÇ3Å=ñi¡ÞÍÂULKSyÎSNÖÑø/cfœ,\:÷BÍ:·±¨€Q™n' ׃.•ånL£7¤I8Vá0emÀ%­ ×/~ÀÕÐ/kìp§3Qm)/â8'µXz‚S©‘Ù0Q°þs!xß´ ('˜ #ÌçÕ}›’rÈœ.]zNÓjDŒ õEz!‡žœY´il÷œ/mÇö>¬þ£1W]–CJþÓ8Á?1ưÙÊÀù¦Gi +SéÒµÔó;Ñf»Š<Úoy<¬ð7‘÷b·g¤†îÀ%“ù‰YxB UJäRŽåÙè÷ø¯%³ëà±uiä»QàVMŠeö–cúô!|ùó?Ê…ÊA7(R„h½OSÑø)LPæ,þ‡R_V“~“ é³¾†ã-Õ^¯øæã«®ßoH010!0 +úŒ àheíløéÇš=·.D{‘<ó¸vàqpid-proton-0.14.0/examples/cpp/ssl_certs/tserver-certificate.pem0000644000175000017500000000220712770711155024407 0ustar danieldaniel-----BEGIN CERTIFICATE----- MIIDKzCCAhOgAwIBAgIJAPnYOOQCJ3kDMA0GCSqGSIb3DQEBCwUAMCwxFDASBgNV BAMMC3Rlc3Rfc2VydmVyMRQwEgYDVQQLDAtwcm90b25fdGVzdDAeFw0xNTExMjcx ODEwMzlaFw0yNTExMjQxODEwMzlaMCwxFDASBgNVBAMMC3Rlc3Rfc2VydmVyMRQw EgYDVQQLDAtwcm90b25fdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC ggEBAKJNB78lgw4KtXDAvXocTLud6mbn6zgfB6ETIF+kcrukOH9DnPxjLBBM4Lig sp1+kmeudFK5/X8riDrvIW52b/rlEBLgLB+oDtI74m6OTbBs9L+FUFYOuxApetQF qoJy2vf9pWfy4uku24vCpeo7eVLi6ypu4lXE3LR+Km3FruHI1NKonHBMhwXSOWqF pYM6/4IZJ4fbV0+eU0Jrx+05s6XHg5vone2BVJKxeSIBje+zWnNnh8+qG0Z70Jgp aMetME5KGnLNgD1okpH0vb3lwjvuqkkx4WswGVZGbLLkSqqBpXPyM9fCFVy5aKSL DBq7IABQtO67O2nBzK3OyigHrUUCAwEAAaNQME4wHQYDVR0OBBYEFGV1PY0FCFbJ gpcDVKI6JGiRTt3kMB8GA1UdIwQYMBaAFGV1PY0FCFbJgpcDVKI6JGiRTt3kMAwG A1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEBAIx1TOTGWnnbpan4bse7wuvH GYSNDJhoTVS+X1TC63xukJD1JBAsCNTqg/ZV6lN3XEl7vvOXfGoCiyXM6a9XOKUo gSDtMrIr+wTh6Ss1yRO8QcCJmxH5JDXNu1ojtwsjFW/vneI4IL9kwpDsSlMQEX/E EkkQwtAx/Cvfe7pecZL4qSeykJOUMTts9H8fCAZqEiRZBA3ugJxqF8jwLP3DoFVQ 6QZzKDY6CSPqfMnVb5i0MAIYVDpau+e3N9dgQpZD22F/zbua0OVbfAPdiRMnYxML FT4sxLnh+5YVqwpVWbEKp4onHe2Fq6YIvAxUYAJ3SBA2C8O2RAVKWxf1jko3jYI= -----END CERTIFICATE----- qpid-proton-0.14.0/examples/cpp/ssl_certs/tserver-full.p120000644000175000017500000000465412770711155022720 0ustar danieldaniel0‚ ¨0‚ n *†H†÷  ‚ _‚ [0‚ W0‚ï *†H†÷  ‚à0‚Ü0‚Õ *†H†÷ 0 *†H†÷  0ùxåÞ`’€‚¨CùÚZ¯­©N(´„ ©éɘõ?Ýè¾DÇ 2íËà0!õºß·uü»fÅ ÷‚¶ò󚓜Néͨ!`öRÎ,Â0F©ò-{¬æû6¤$Âhû1ÍäŸþCn-7bCP³ù®èzݹâæÑoÙÊEKK|̇'§Ka<´¹é‚¶uz¡ˆÆ)Ç£A¶êšÞ6¢§ºƒ«ªhžÄâ:~o¦]Q €q5ËÅ îõd@Í[û„sP-ÏT 2 9F¥©¶ÉÇ3™h¦NÚ¸(ÐÙ[ŽÕ?41*Ϫ°=oÅ­‰í êzµ>=ªYäÂ(ÔÞ¸¤utRû<åÃéè/8*Üà§åâî È)1‚Z[‘AOè•&x¼Ùƒ7ø8Íõ$7W/±¿ƒ¿3ܸzéßli¾!NfÕ–pbQwUpœÚ”ʉ™?Ï‘$·|…ýñ‚ê ¦Is-~, lÔÂêKUq1\iªÊœ Œ¥+>•à‘Eœš9D‡Q:Í4Õcóá IÇ>t¯dÍ3íȉp¢J¢Éþ××F%Ø¢AÀ×IÖyì† `]âÙþäpÚ_Cn›A/Ä€â™Ë7Cá`N>klMì^LV¦ÛjîÒpKÈ„µ²R%ãxœ:7 3¢ÿãÕ=}‚¶8Ná¢X>÷¶8û ))²Ó –"P-…•·aoÖVTùò’BXnõ7íÂq#T¶%C'ˆò‡&|Á®3Y¾GH+U wóñ#I¾…ä¿“öÆzOˆ˜%¥Ú–"›ÙCa‹f‰:1ð¬:âÚa¥fxpzù¥wÄëÐj~óÄä{»=¿Œ“–D¨ pܨ.NêÂ/ç˜a*®±’Û…ù©åÀl[‚•Úç Íyæen’XfÎO×(*1Ù}ãůt \&±®¦ó!ÁÆV_9Q¥£ºº‡r܆­hY¨·x÷Ë"Å…Œöž+nøF²-ê(ÔZïÖ)­À›Y³8u° •¸ó’ôïÇ>ÇÞ?Y†"ƒY†ãö,å™7F•¹ÀØÊ³&G!¥²ít„ ¹Ía/Ûá±j™zF,Ç"²¸¦äíâÌlúòù©ù”˜'Ï©< ~üNy–Ê*¬wT?}dm±¹AÒ3)ÈŽý$…c¼‹E*ö•›Ô7Í[UŒ©£ýð’}FœZC]þt"óÚ7HÔ ”A3 LœÁð\›™DJy0‚` *†H†÷  ‚Q‚M0‚I0‚E *†H†÷   ‚î0‚ê0 *†H†÷  0ü¿É¹ÂK>‚È"ÛâŠþ»bÊÖþa´eç~ÕGãßo8ÃoŽ—¡›êJ P&°ØÒ(’¸´±ƒX:kHðúƒÏüÐÕçòÝ|ö,†H4Üc£Sôtl]Û»Hò¬¶„ŒkÑ{¤ÜCØmÈSþËwé§ŒGki‚Ü3£¾n&¥NtÛ~•9ÆT2Xåø E׎sæf“VrèÈ»†æ˜)¨ýÀ‚Ðã+«ÙcL‹6dS€OŽÖÕ`"ŽürâE1gÇø\9Ї½‚Øõëï~i·ÿïŽ|CÊCè;ÅÙ¼èêC<>Ž×®àÀßB=.L‚½Û# ,ÁÖ¨Â%©pñ·™çu¢\Ýf|iŽßïTh·áP‡]TmÅ4tÜb?2Q9út­Ä›ª¶Xs¥îqî²Ë#t ` ß8ã zð¿Íð.»‘—ÕðÔ¿I‡‰ë7M Á÷æÛGGºz­G çºbbì’ÁŸYÏ¥=¼«·ðÜÍí¹žõýÍÁÞ%˜×¶bhðëC.iIp…x:&ûª+Ñ0¬ …`Æ&ª’¶Âìé³)T·ºÇ›a9æ€~Q ò¼“¹š}Ú#ÿ»?0¾$,”Rlf-.@~8ÐÜ0ðíø}5îã4Mw¤‡Øöýfzm`<"'×x–Ø]µ4/.ö3k'ü›º!@ð[§?|¤Ñ[=tä›Ã5¶¤×œ"{T $‘íiÙ/Ùö1¶»9/N·"ÃÊè@¿@¾‰¼¬ÛˆGçÏM¹]Ô]l!åW#khüŽ¿¥ mmÚÚ¬%+Ü“.qéŸãѽöb;4flDøñ ²épÕEö%öÒ‡r·^л>Lf7íõZœ¼¯ÉhK‰=ú"ÇGüÆGÝìÍÕÒ²ÛGY'F%¿Ï$›(+óDç²—ƒúÍô âÆà‡lŸ9L¸éFÚ4üOІ|ý`€wÞ®&Å" z>v°ô‡cÈ “ËuÞðÚ\NCÛëòzV¼ŠÈšW½¢5ñŽ˜‰ùý®«'Qëý!®N4ºøÿ€”sH’¸8‹:_¥ÿâû;ð¹éÏVi@ÛaEIówîdݯ7(œÅé[Žö{„{‚-yU -\~¬E«æU·Uáè÷u‡qåppkÉ:.‘¥z4pÛ6¾[GVæ v›j ðšœB5DÚÅ‘fn VPx 7ï’w©ú»d™,Ž´…]71\¬S…c`0(±H´u ‹²‘;eëèyŸä+ÏËÂõ¤ciÇF‚x…·oX âÇþÈ]‚ØL>ô¾2.V^Т~hI?uDÓq{Ò7`dthö:K3®DüýŒàpºgÕ`%ͬtL&ò§¥x,4»‚…ˆ’Za4k3]Mä ß{”Kd[@ã,ƒ’ÀCYï;é7f¨Ûv'+ŽVâ 'st¬|ç "©ä^z[;Ô-qpid-proton-0.14.0/examples/cpp/ssl_certs/tserver-private-key.pem0000644000175000017500000000345212770711155024370 0ustar danieldaniel-----BEGIN ENCRYPTED PRIVATE KEY----- MIIFDjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQI1cT0c2J3GcQCAggA MBQGCCqGSIb3DQMHBAi1hxSX2LJ+EgSCBMheHJ0iXr5A36Natjk/LcAEeKUMT9s+ sMzoQceCWe8qMlQluWksr9iDdZ4JRIE8cpK8dbmx4dLY/SShUzdlhJHCSa4zZBHq 8cZ/jGUF/RF1rqdgjK589eUq+uOl3/gXKzG/SxBqayy6PSn12kX3qnvmlkXCmtwU lg+iBm5wRcJ0MyVHaJkyA8sW8gr186C/VAau6Yu0crQXN7NRo9snrd4ewuYMIEhZ hgaG9XsYQWB1bPhAaKj80CZGxsQbJyTwcbKKkB3IY4WXx8mmhuiNl+vKT3HBJ9Ju YB6tgIjs8CJ4X2P4aU3yNJwG1QldgHSqmFGQ19bcZAw3s3kzwjdzRf4H2V16XOBd zQ5AEs/ffVMzMIAfkb1gYwgunZ2CVwwDJ2mi1RcgkX+Og2aFQc+fxXcVOnDcGLxV 6fuCuZ2lsXfoiIyRh9kj3L75N12GtVUvgBdnMuOc1wPw6XnGQtDwt0acJpdexLMG k0j57r/gcgzTcmF3qNM+y9L/HLssgrJkvVJw2Np5gmtIyfDocsDUWUbClS4dTpYf oTngUTU+vWtHBuaUnb+f5/WJaRS/S7mmR8usbVG3i9WnEr/vlPJpbJFSjW2S6u/H 7cFxKUmmBZsSuEv/EKt9a+Sh62kprOChm4myqfCI1/gvNKfUZC6m0Vp8zf+2LgAq 2RgbMuqysMjWUtV4kDRZT7oCYckUDwsCHdbLES3nmVrtBk2ShMKHBpDp8/GoRuiV jdV7/EjKM/M1kXtFYYe3z7Mxv++lKYIJ7bNwVrQ8nrhce/VwHw6D5emWXNCJXhKZ FW7EM2ZOZ9eaKOlCsIi8sbjV6Yie9IY6HJKKmi3CpO0Tv5kLBdHkru8vGCSFm3O1 n7wz7Ys5FBSlZ19X0NwQSCQX1Q4w+tido6i1SCRX0qJEdTNGuGwVXMHCf4/1zyHV hj8vnxh8fzo79LFrwlTTgwLg1Mr8sEUFFDJ/raJ1AhFXi8n24trtNR8EHxRW8wtD CLCKaqkEqfBiFXK/Yq3RrefCayPHiD+DaNsI8BwefMGpED3vD8YYCjAzXNPh/CSF sc1i1jWMzbJhzOoFSPNXhlfusbUFMFQ/6olatmH47SY6HBBOL3DDP5uQ0jw8P454 QBjlMOpEZmZxO6TcEtJwu0vzgog4rQ5g3NWy6SIpjWehNwTynLt7yM3R5WTI6cZs 0GTv/rqo2/SUoNsFmnGIUwj/DrBe4XOAq1nS2ZlEctxKhBsKH0hMFp6D1rXOzrgl bwcq+oistoB0TLcThShyNgSqzW1znQ1n5SVUk9b5rRhSttJxn3yOMewH0i3v8bPo HOhP5kaGjblPsCYyhlL/SNVF0OXEGTwLNey7FQdWFOwVwTRRXe7k+uGZ2d5hg+Jn It/trDZ1RDYbVmB7/Qy73c16J4mvhOUJ2de5ZciFBjkidbiiUKLj9xnjK9k9Sauo MKhNnDMAEU5VDQM3xNe5BRdX8dFLwfF5H64sU3nROF83aUnDgvfFEowYPnCuPYfm m4aQHfoBSg4j3v1OeOwktcl+Q2TjxPHfWhbWeRBfxOTqQ/suYhnQChuFSK/qyo9K ccgotqghhunRsWMoZT25H7AZM6yKb1sMz/0oyMRIKeGqoYh+ULM5XLY0xNYd4/xU WtQ= -----END ENCRYPTED PRIVATE KEY----- qpid-proton-0.14.0/examples/cpp/ssl_client_cert.cpp0000644000175000017500000001623312770711155021615 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include #include #include #include #include "fake_cpp11.hpp" using proton::connection_options; using proton::ssl_client_options; using proton::ssl_server_options; using proton::ssl_certificate; using proton::sasl; // Helper functions defined below. bool using_OpenSSL(); std::string platform_CA(const std::string &base_name); ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd); static std::string cert_directory; static std::string find_CN(const std::string &); struct server_handler : public proton::messaging_handler { proton::listener listener; void on_connection_open(proton::connection &c) OVERRIDE { std::cout << "Inbound server connection connected via SSL. Protocol: " << c.transport().ssl().protocol() << std::endl; if (c.transport().sasl().outcome() == sasl::OK) { std::string subject = c.transport().ssl().remote_subject(); std::cout << "Inbound client certificate identity " << find_CN(subject) << std::endl; } else { std::cout << "Inbound client authentication failed" < 1 ? argv[1] : "amqps://127.0.0.1:8888/examples"; // Location of certificates and private key information: if (argc > 2) { cert_directory = argv[2]; size_t sz = cert_directory.size(); if (sz && cert_directory[sz -1] != '/') cert_directory.append("/"); } else cert_directory = "ssl_certs/"; hello_world_direct hwd(url); proton::default_container(hwd).run(); return 0; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } bool using_OpenSSL() { // Current defaults. #if defined(WIN32) return false; #else return true; #endif } ssl_certificate platform_certificate(const std::string &base_name, const std::string &passwd) { if (using_OpenSSL()) { // The first argument will be the name of the file containing the public certificate, the // second argument will be the name of the file containing the private key. return ssl_certificate(cert_directory + base_name + "-certificate.pem", cert_directory + base_name + "-private-key.pem", passwd); } else { // Windows SChannel // The first argument will be the database or store that contains one or more complete certificates // (public and private data). The second will be an optional name of the certificate in the store // (not used in this example with one certificate per store). return ssl_certificate(cert_directory + base_name + "-full.p12", "", passwd); } } std::string platform_CA(const std::string &base_name) { if (using_OpenSSL()) { // In this simple example with self-signed certificates, the peer's certificate is the CA database. return cert_directory + base_name + "-certificate.pem"; } else { // Windows SChannel. Use a pkcs#12 file with just the peer's public certificate information. return cert_directory + base_name + "-certificate.p12"; } } std::string find_CN(const std::string &subject) { // The subject string is returned with different whitespace and component ordering between platforms. // Here we just return the common name by searching for "CN=...." in the subject, knowing that // the test certificates do not contain any escaped characters. size_t pos = subject.find("CN="); if (pos == std::string::npos) throw std::runtime_error("No common name in certificate subject"); std::string cn = subject.substr(pos); pos = cn.find(','); return pos == std::string::npos ? cn : cn.substr(0, pos); } qpid-proton-0.14.0/examples/cpp/tutorial.dox0000644000175000017500000003502712770711155020316 0ustar danieldaniel// -*-markdown-*- // NOTE: doxygen can include markdown pages directly but there seems to be a bug // that shows messed-up line numbers in \skip \until code extracts. This file // is markdown wrapped in a doxygen comment - which works. The file is best viewed/editied // as markdown. /** @page tutorial Tutorial This is a brief tutorial that will walk you through the fundamentals of building messaging applications in incremental steps. There are further examples, in addition the ones mentioned in the tutorial. Proton provides an "event-driven" programming model, where you implement a subclass of `proton::messaging_handler` and override functions that react to various AMQP events (connections opening and closing, messages being delivered, and so on). The examples below show how to implement handlers for clients and servers and how to run them using the `proton::default_container`, a portable, easy-to-use way to build single-threaded clients or servers. Some of the examples require an AMQP *broker* that can receive, store, and send messages. @ref broker.hpp and @ref broker.cpp define a simple example broker. If run without arguments, it listens on `0.0.0.0:5672`, the standard AMQP port on all network interfaces. To use a different port or network interface: broker -a : Instead of the example broker, you can use any AMQP 1.0-compliant broker. You must configure your broker to have a queue (or topic) named "examples". The `helloworld` examples take an optional URL argument. The other examples take an option `-a URL`. A URL looks like this: HOST:PORT/ADDRESS It usually defaults to `127.0.0.1:5672/examples`, but you can change this if your broker is on a different host or port, or you want to use a different queue or topic name (the ADDRESS part of the URL). URL details are at `proton::url`. Hello World! ------------ \dontinclude helloworld.cpp Tradition dictates that we start with Hello World! This example demonstrates sending and receiving by sending a message to a broker and then receiving the same message back. In a realistic system the sender and receiver would normally be in different processes. The complete example is @ref helloworld.cpp We will include the following classes: `proton::default_container` (an implementation of `proton::container`) runs an event loop which dispatches events to a `proton::messaging_handler`. This allows a *reactive* style of programming which is well suited to messaging applications. `proton::connection` and `proton::delivery` are AMQP entities used in the handler functions. `proton::url` is a simple parser for the URL format mentioned above. \skip proton/connection \until proton/url We will define a class `hello_world` which is a subclass of `proton::messaging_handler` and overrides functions to handle the events of interest in sending and receiving a message. \skip class hello_world \until {} `proton::messaging_handler::on_container_start()` is called when the event loop first starts. We handle that by establishing a connection and creating a sender and a receiver. \skip on_container_start \until } \until } `proton::messaging_handler::on_sendable()` is called when the message can be transferred over the associated sender link to the remote peer. We create a `proton::message`, set the message body to `"Hello World!"`, and send the message. Then we close the sender, since we only want to send one message. Closing the sender will prevent further calls to `proton::messaging_handler::on_sendable()`. \skip on_sendable \until } `proton::messaging_handler::on_message()` is called when a message is received. We just print the body of the message and close the connection, as we only want one message \skip on_message \until } The message body is a `proton::value`, see the documentation for more on how to extract the message body as type-safe C++ values. Our `main` function creates an instance of the `hello_world` handler and a `proton::default_container` using that handler. Calling `proton::container::run` sets things in motion and returns when we close the connection as there is nothing further to do. It may throw an exception, which will be a subclass of `proton::error`. That in turn is a subclass of `std::exception`. \skip main \until } \until } \until } Hello World, direct! -------------------- \dontinclude helloworld_direct.cpp Though often used in conjunction with a broker, AMQP does not *require* this. It also allows senders and receivers to communicate directly if desired. We will modify our example to send a message directly to itself. This is a bit contrived but illustrates both sides of the direct send and receive scenario. The full code is at @ref helloworld_direct.cpp. The first difference is that, rather than creating a receiver on the same connection as our sender, we listen for incoming connections by invoking the `proton::container::listen()` method on the container. \skip on_container_start \until } As we only need then to initiate one link, the sender, we can do that by passing in a url rather than an existing connection, and the connection will also be automatically established for us. We send the message in response to the `proton::messaging_handler::on_sendable()` callback and print the message out in response to the `proton::messaging_handler::on_message()` callback exactly as before. \skip on_sendable \until } \until } However, we also handle two new events. We now close the connection from the sender's side once the message has been accepted. The acceptance of the message is an indication of successful transfer to the peer. We are notified of that event through the `proton::messaging_handler::on_tracker_accept()` callback. \skip on_tracker_accept \until } Then, once the connection has been closed, of which we are notified through the `proton::messaging_handler::on_connection_close()` callback, we stop accepting incoming connections. A that point there is no work to be done, the event loop exits, and the `proton::container::run()` method returns. \skip on_connection_close \until } So now we have our example working without a broker involved! Note that for this example we pick an "unusual" port 8888 since we are talking to ourselves rather than a broker. \skipline url = Asynchronous send and receive ----------------------------- Of course, these `Hello World!` examples are very artificial, communicating as they do over a network connection but with the same process. A more realistic example involves communication between separate processes, which could indeed be running on completely separate machines. Let's separate the sender from the receiver, and transfer more than a single message between them. We'll start with a simple sender, @ref simple_send.cpp. \dontinclude simple_send.cpp As with the previous example, we define the application logic in a class that handles events. Because we are transferring more than one message, we need to keep track of how many we have sent. We'll use a `sent` member variable for that. The `total` member variable will hold the number of messages we want to send. \skip class simple_send \until total As before, we use the `proton::messaging_handler::on_container_start()` event to establish our sender link over which we will transfer messages. \skip on_container_start \until } AMQP defines a credit-based flow-control mechanism. Flow control allows the receiver to control how many messages it is prepared to receive at a given time and thus prevents any component being overwhelmed by the number of messages it is sent. In the `proton::messaging_handler::on_sendable()` callback, we check that our sender has credit before sending messages. We also check that we haven't already sent the required number of messages. \skip on_sendable \until } \until } The `proton::sender::send()` call above is asynchronous. When it returns, the message has not yet actually been transferred across the network to the receiver. By handling the `proton::messaging_handler::on_tracker_accept()` event, we can get notified when the receiver has received and accepted the message. In our example we use this event to track the confirmation of the messages we have sent. We only close the connection and exit when the receiver has received all the messages we wanted to send. \skip on_tracker_accept \until } \until } If we are disconnected after a message is sent and before it has been confirmed by the receiver, it is said to be "in doubt". We don't know whether or not it was received. In this example, we will handle that by resending any in-doubt messages. This is known as an "at-least-once" guarantee, since each message should eventually be received at least once, though a given message may be received more than once (i.e., duplicates are possible). In the `proton::messaging_handler::on_transport_close()` callback, we reset the sent count to reflect only those that have been confirmed. The library will automatically try to reconnect for us, and when our sender is sendable again, we can restart from the point we know the receiver got to. \skip on_transport_close \until } \dontinclude simple_recv.cpp Now let's look at the corresponding receiver, @ref simple_recv.cpp. This time we'll use an `expected` member variable for for the number of messages we expect and a `received` variable to count how many we have received so far. \skip class simple_recv \until received We handle `proton::messaging_handler::on_container_start()` by creating our receiver, much like we did for the sender. \skip on_container_start \until } We also handle the `proton::messaging_handler::on_message()` event for received messages and print the message out as in the `Hello World!` examples. However, we add some logic to allow the receiver to wait for a given number of messages and then close the connection and exit. We also add some logic to check for and ignore duplicates, using a simple sequential ID scheme. \skip on_message \until } Direct send and receive ----------------------- Sending between these two examples requires an intermediary broker since neither accepts incoming connections. AMQP allows us to send messages directly between two processes. In that case, one or other of the processes needs to accept incoming connections. Let's create a modified version of the receiving example that does this with @ref direct_recv.cpp. \dontinclude direct_recv.cpp There are only two differences here. Instead of initiating a link (and implicitly a connection), we listen for incoming connections. \skip on_container_start \until } When we have received all the expected messages, we then stop listening for incoming connections by calling `proton::listener::stop()` \skip on_message \until } \until } \until } \until } You can use the @ref simple_send.cpp example to send to this receiver directly. (Note: you will need to stop any broker that is listening on the 5672 port, or else change the port used by specifying a different address to each example via the `-a` command-line switch). We can also modify the sender to allow the original receiver to connect to it, in @ref direct_send.cpp. Again, that requires just two modifications: \dontinclude direct_send.cpp As with the modified receiver, instead of initiating establishment of a link, we listen for incoming connections. \skip on_container_start \until } When we have received confirmation of all the messages we sent, we call `container::listener::stop()` to exit. \skip on_tracker_accept \until } \until } To try this modified sender, run the original @ref simple_recv.cpp against it. The symmetry in the underlying AMQP wire protocol that enables this is quite unique and elegant, and in reflecting this the Proton API provides a flexible toolkit for implementing all sorts of interesting intermediaries. Request and response -------------------- A common pattern is to send a request message and expect a response message in return. AMQP has special support for this pattern. Let's have a look at a simple example. We'll start with @ref server.cpp, the program that will process the request and send the response. Note that we are still using a broker in this example. Our server will provide a very simple service: it will respond with the body of the request converted to uppercase. \dontinclude server.cpp \skip class server \until }; The code here is not too different from the simple receiver example. However, when we receive a request in `proton::messaging_handler::on_message`, we look at the `proton::message::reply_to` address and create a sender with that address for the response. We'll cache the senders in case we get further requests with the same `reply_to`. Now let's create a simple @ref client.cpp to test this service out. \dontinclude client.cpp Our client takes a list of strings to send as requests. \skipline client( Since we will be sending and receiving, we create a sender and a receiver in `proton::messaging_handler::on_container_start`. Our receiver has a blank address and sets the `dynamic` flag to true, which means we expect the remote end (the broker or server) to assign a unique address for us. \skip on_container_start \until } Now we need a function to send the next request from our list of requests. We set the `reply_to` address to be the dynamically assigned address of our receiver. \skip send_request \until } We need to use the address assigned by the broker as the `reply_to` address of our requests, so we can't send them until our receiver has been set up. To do that, we add an `proton::messaging_handler::on_receiver_open()` method to our handler class and use that as the trigger to send our first request. \skip on_receiver_open \until } When we receive a reply, we send the next request. \skip on_message \until } \until } \until } Direct request and response --------------------------- We can avoid the intermediary process by writing a server that accepts connections directly, @ref server_direct.cpp. It involves the following changes to our original server: \dontinclude server_direct.cpp Our server must generate unique `reply-to` addresses for links from the client that request a dynamic address (previously this was done by the broker). We use a simple counter. \skip generate_address \until } Next we need to handle incoming requests for links with dynamic addresses from the client. We give the link a unique address and record it in our `senders` map. \skip on_sender_open \until } Note that we are interested in *sender* links above because we are implementing the server. A *receiver* link created on the client corresponds to a *sender* link on the server. Finally when we receive a message we look up its `reply_to` in our senders map and send the reply. \skip on_message \until } \until } \until } */ qpid-proton-0.14.0/proton-c/0000755000175000017500000000000012770711157015073 5ustar danieldanielqpid-proton-0.14.0/proton-c/.gitignore0000644000175000017500000000013412770711155017057 0ustar danieldaniel*.pyc *.o *.d src/codec/encodings.h src/protocol.h src/proton src/test src/libqpidproton.so qpid-proton-0.14.0/proton-c/bindings/0000755000175000017500000000000012770711156016667 5ustar danieldanielqpid-proton-0.14.0/proton-c/bindings/javascript/0000755000175000017500000000000012770711155021034 5ustar danieldanielqpid-proton-0.14.0/proton-c/bindings/javascript/LICENSE0000644000175000017500000002613712770711155022052 0ustar danieldaniel 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. qpid-proton-0.14.0/proton-c/bindings/javascript/README0000644000175000017500000004254512770711155021726 0ustar danieldanielQpid Proton JavaScript Language Bindings ======================================== The code contained herein provides JavaScript language bindings for working with the Qpid Proton AMQP 1.0 protocol engine and messenger library. Important Note - Modern Browser Needed ====================================== The JavaScript binding requires ArrayBuffer/TypedArray and WebSocket support. Both of these are available in most "modern" browser versions. The author has only tried running on FireFox and Chrome, though recent Safari, Opera and IE10+ *should* work too - YMMV. It might be possible to polyfill for older browsers but the author hasn't tried this. Important Note - WebSocket Transport!!! ======================================= Before going any further it is really important to realise that the JavaScript bindings to Proton are somewhat different to the bindings for other languages because of the restrictions of the execution environment. In particular it is very important to note that the JavaScript bindings by default use a WebSocket transport and not a TCP transport, so whilst it's possible to create Server style applications that clients can connect to (e.g. recv.js and send.js) note that: JavaScript clients cannot *directly* talk to "normal" AMQP applications such as qpidd or (by default) the Java Broker because they use a standard TCP transport. This is a slightly irksome issue, but there's no getting away from it because it's a security restriction imposed by the browser environment. At the moment even for Node.js we are limited to using a WebSocket transport, but it is on the author's "TODO" list to look at providing a means to use either a WebSocket transport or a native TCP transport (via node's net library). It should also be possible to use native TCP for Chrome "packaged apps", but again this is only on the TODO list so if you want to talk to a "normal" AMQP application you must live with the WebSocket constraints. Option 1. proxy from WebSockets to TCP sockets. The application /examples/messenger/javascript/proxy.js is a simple Node.js WebSocket<->TCP Socket proxy, simply doing: node proxy.js will stand up a proxy listening by default on WebSocket port 5673 and forwarding to TCP port 5672 (this is configurable, for options do: node proxy.js -h) Rather than using a stand-alone proxy it is possible to have applications stand up their own proxy (where lport = listen port, thost = target host and tport = target port): var proxy = require('./ws2tcp.js'); proxy.ws2tcp(lport, thost, tport); For talking to the C++ broker unfortunately proxying is currently the only option as qpidd does not have a WebSocket transport. Option 2. The Java Broker's WebSocket transport. Recent releases of the Qpid Java Broker provide a native WebSocket transport which means that the JavaScript binding can talk to it with no additional requirements. It is necessary to configure the Java Broker as the WebSocket transport is not enabled by default. In /config.json in the "ports" array you need to add: { "authenticationProvider" : "passwordFile", "name" : "AMQP-WS", "port" : "5673", "transports" : [ "WS" ] } This sets the JavaBroker to listen on WebSocket port 5673 similar to the proxy. One gotcha that still bites the author *** DO NOT FORGET *** that you will be using ports that you are not used to!! If you are not connecting check that the proxy is running and that you are specifying the right ports. I still mess up :-( WebRTC Transport ================ A WebRTC Transport is supported by emscripten, though the author has not tried it. If you wan to play with this you are very much on your own at the moment YMMV. This is configured by adding to the LINK_FLAGS in CMakeLists.txt -s \"SOCKET_WEBRTC=1\" /* WebRTC sockets supports several options on the Module object. * Module['host']: true if this peer is hosting, false otherwise * Module['webrtc']['broker']: hostname for the p2p broker that this peer should use * Module['webrtc']['session']: p2p session for that this peer will join, or undefined if this peer is hosting * Module['webrtc']['hostOptions']: options to pass into p2p library if this peer is hosting * Module['webrtc']['onpeer']: function(peer, route), invoked when this peer is ready to connect * Module['webrtc']['onconnect']: function(peer), invoked when a new peer connection is ready * Module['webrtc']['ondisconnect']: function(peer), invoked when an existing connection is closed * Module['webrtc']['onerror']: function(error), invoked when an error occurs */ If you wanted to play with these you'd likely have to tweak the module.js code in /proton-c/bindings/javascript The emscripten documentation is a bit light on the WebRTC Transport too, though emscripten/tests/test_sockets.py emscripten/tests/sockets/webrtc_host.c emscripten/tests/sockets/webrtc_peer.c emscripten/tests/sockets/p2p/broker/p2p-broker.js emscripten/tests/sockets/p2p/client/p2p-client.js Look like they provide a starting point. Very much TODO...... Creating The Bindings ===================== To generate the JavaScript bindings we actually cross-compile from proton-c You will need to have emscripten (https://github.com/kripken/emscripten) installed to do the cross-compilation and in addition you will require a few things that emscripten itself depends upon. http://kripken.github.io/emscripten-site/docs/building_from_source/index.html#installing-from-source http://kripken.github.io/emscripten-site/docs/building_from_source/toolchain_what_is_needed.html provide instructions for installing emscripten and the "fastcomp" LLVM backend. This approach lets users use the "bleeding edge" version of emscripten on the "incoming" branch (pretty much analogous to building qpid/proton off svn trunk). This is the approach that the author of the JavaScript Bindings tends to use. http://kripken.github.io/emscripten-site/docs/getting_started/downloads.html provides some fairly easy to follow instructions for getting started on several platforms the main dependencies are as follows (on Windows the SDK includes these): * The Emscripten code, from github (git clone git://github.com/kripken/emscripten.git). * LLVM with Clang. Emscripten uses LLVM and Clang, but at the moment the JavaScript back-end for LLVM is off on a branch so you can't use a stock LLVM/Clang. http://kripken.github.io/emscripten-site/docs/building_from_source/LLVM-Backend.html http://kripken.github.io/emscripten-site/docs/building_from_source/building_fastcomp_manually_from_source.html#building-fastcomp-from-source has lots of explanation and some easy to follow instructions for downloading and building fastcomp * Node.js (0.8 or above; 0.10.17 or above to run websocket-using servers in node) * Python 2.7.3 * Java is required in order to use the Closure Compiler to minify the code. If you haven't run Emscripten before it's a good idea to have a play with the tutorial here: http://kripken.github.io/emscripten-site/docs/getting_started/Tutorial.html when you are all set up with emscripten and have got the basic tests in the tutorial running building Proton should be simple, simply go to the Proton root directory and follow the main instructions in the README there, in precis (from the root directory) it's: mkdir build cd build cmake .. make and you should be all set, to test it's all working do (from the build directory): cd proton-c/bindings/javascript/examples node recv-async.js in one window and node send-async.js in another. These examples are actually JavaScript applications that have been directly compiled from recv-async.c and send-async.c in /examples/messenger/c if you'd prefer to write applications in C and compile them to JavaScript that is a perfectly valid approach and these examples provide a reasonable starting point for doing so. Documentation ============= When you've successfully got a working build do: make docs Which will make all of the proton documentation including the JavaScript docs. If successful the JSDoc generated documentation should be found here: /build/proton-c/bindings/javascript/html/index.html Using "native" JavaScript ========================= The examples in /examples/messenger/javascript are the best starting point. In practice the examples follow a fairly similar pattern to the Python bindings the most important thing to bear in mind though is that JavaScript is completely asynchronous/non-blocking, which can catch the unwary. An application follows the following (rough) steps: 1. (optional) Set the heap size. It's important to realise that most of the library code is compiled C code and the runtime uses a "virtual heap" to support the underlying malloc/free. This is implemented internally as an ArrayBuffer with a default size of 16777216. To allocate a larger heap an application must set the PROTON_TOTAL_MEMORY global. In Node.js this would look like (see send.js): PROTON_TOTAL_MEMORY = 50000000; // Note no var - it needs to be global. In a browser it would look like (see send.html): 2. Load the library and create a message and messenger. In Node.js this would look like (see send.js): var proton = require("qpid-proton-messenger"); var message = new proton.Message(); var messenger = new proton.Messenger(); In a browser it would look like (see send.html): Load the library and create a message and messenger. In Node.js this would look like (see send.js): var proton = require("qpid-proton-messenger"); var message = new proton.Message(); var messenger = new proton.Messenger(); In a browser it would look like (see send.html):
qpid-proton-0.14.0/tests/javascript/msgr-send.js0000755000175000017500000000736212770711161021105 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var usage = 'Usage: msgr-send [OPTIONS]\n' + ' -a [,]* \tThe target address [amqp://~0.0.0.0]\n' + ' -c # \tNumber of messages to send before exiting [0=forever]\n' + ' -b # \tSize of message body in bytes [1024]\n' + ' -p # \tSend batches of # messages (wait for replies before sending next batch if -R) [1024]\n' + ' -w # \tSize for outgoing window [0]\n' + ' -e # \t# seconds to report statistics, 0 = end of test [0] *TBD*\n' + ' -R \tWait for a reply to each sent message\n' + ' -B # \tArgument to Messenger::recv(n) [-1]\n' + ' -N \tSet the container name to \n' + ' -V \tEnable debug logging\n'; // Increase the virtual heap available to the emscripten compiled C runtime. // This allows us to test a really big string. PROTON_TOTAL_MEMORY = 140000000; PROTON_TOTAL_STACK = 25000000; // Needs to be bigger than the biggest string. var proton = require("qpid-proton-messenger"); var benchmark = require("./msgr-send-common.js"); var opts = {}; opts.addresses = 'amqp://0.0.0.0'; opts.messageCount = 0; opts.messageSize = 1024; opts.recvCount = -1; opts.sendBatch = 1024; opts.outgoingWindow; opts.reportInterval = 0; opts.getReplies = false; opts.name; opts.verbose = false; var args = process.argv.slice(2); if (args.length > 0) { if (args[0] === '-h' || args[0] === '--help') { console.log(usage); process.exit(0); } for (var i = 0; i < args.length; i++) { var arg = args[i]; if (arg.charAt(0) === '-') { if (arg === '-V') { opts.verbose = true; } else if (arg === '-R') { opts.getReplies = true; } else { i++; var val = args[i]; if (arg === '-a') { opts.addresses = val; } else if (arg === '-c') { opts.messageCount = val; } else if (arg === '-b') { opts.messageSize = val; } else if (arg === '-B') { opts.recvCount = val; } else if (arg === '-p') { opts.sendBatch = val; } else if (arg === '-w') { opts.outgoingWindow = val; } else if (arg === '-e') { opts.reportInterval = val; } else if (arg === '-N') { opts.name = val; } } } } } var sender = new benchmark.MessengerSend(opts); sender.start(); } else { console.error("msgr-send.js should be run in Node.js"); } qpid-proton-0.14.0/tests/javascript/soak.js0000755000175000017500000000636412770711161020144 0ustar danieldaniel#!/usr/bin/env node /* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ // Check if the environment is Node.js and if not log an error and exit. if (typeof process === 'object' && typeof require === 'function') { var proton = require("qpid-proton-messenger"); var addr = 'guest:guest@localhost:5673'; //var addr = 'localhost:5673'; var address = 'amqp://' + addr; console.log(address); var subscriptionQueue = ''; var count = 0; var start = 0; // Start Time. var message = new proton.Message(); var messenger = new proton.Messenger(); var pumpData = function() { while (messenger.incoming()) { // The second parameter forces Binary payloads to be decoded as strings // this is useful because the broker QMF Agent encodes strings as AMQP // binary, which is a right pain from an interoperability perspective. var t = messenger.get(message, true); //console.log("Address: " + message.getAddress()); //console.log("Content: " + message.body); messenger.accept(t); if (count % 1000 === 0) { var time = +new Date(); console.log("count = " + count + ", duration = " + (time - start) + ", rate = " + ((count*1000)/(time - start))); } sendMessage(); } if (messenger.isStopped()) { message.free(); messenger.free(); } }; var sendMessage = function() { var msgtext = "Message Number " + count; count++; message.setAddress(address + '/' + subscriptionQueue); message.body = msgtext; messenger.put(message); //messenger.settle(); }; messenger.on('error', function(error) {console.log(error);}); messenger.on('work', pumpData); messenger.on('subscription', function(subscription) { var subscriptionAddress = subscription.getAddress(); var splitAddress = subscriptionAddress.split('/'); subscriptionQueue = splitAddress[splitAddress.length - 1]; console.log("Subscription Queue: " + subscriptionQueue); start = +new Date(); sendMessage(); }); //messenger.setOutgoingWindow(1024); messenger.setIncomingWindow(1024); // The Java Broker seems to need this. messenger.recv(); // Receive as many messages as messenger can buffer. messenger.start(); messenger.subscribe('amqp://' + addr + '/#'); } else { console.error("soak.js should be run in Node.js"); } qpid-proton-0.14.0/tests/javascript/unittest.js0000644000175000017500000000276512770711161021064 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /** * The TestCase class provides a simple dependency-free Unit Test framework to * automagically invoke methods that start with "test" on classes that extend it. */ // TestCase Constructor var TestCase = function() {}; // Enumerate all functions of the class and invoke those beginning with "test". TestCase.prototype.run = function() { for (var property in this) { if ((typeof this[property] === 'function') && property.lastIndexOf('test', 0) === 0) { this.setUp(); this[property](); this.tearDown(); } } }; TestCase.prototype.setUp = function() {}; TestCase.prototype.tearDown = function() {}; module.exports.TestCase = TestCase; qpid-proton-0.14.0/tests/python/0000755000175000017500000000000012770711161016010 5ustar danieldanielqpid-proton-0.14.0/tests/python/interop-generate0000755000175000017500000000632712770711161021216 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Generate encoded AMQP fragments for interop testing. import logging, optparse, os, struct, sys, time, traceback, types, cgi from proton import * def main(argv): def write(data, filename): f = open(filename+".amqp", 'w') f.write(data.encode()) f.close() # message m = Message() d = Data() d.put_string("hello") m.body = d.encode() write(m, "message") # null d = Data() d.put_null() write(d, "null") # primitive types d = Data() d.put_bool(True) d.put_bool(False) d.put_ubyte(42) d.put_ushort(42) d.put_short(-42) d.put_uint(12345) d.put_int(-12345) d.put_ulong(12345) d.put_long(-12345) d.put_float(0.125) d.put_double(0.125) write(d, "primitives") # string types d = Data() d.put_binary("abc\0defg") d.put_string("abcdefg") d.put_symbol("abcdefg") d.put_binary("") d.put_string("") d.put_symbol("") write(d, "strings") # described types d = Data() d.put_described() d.enter() d.put_symbol("foo-descriptor") d.put_string("foo-value") d.exit() d.put_described() d.enter() d.put_int(12) d.put_int(13) d.exit() write(d, "described") # described array d = Data() d.put_array(True, Data.INT) d.enter() d.put_symbol("int-array") for i in xrange(0,10): d.put_int(i) d.exit() write(d, "described_array") # Arrays # Integer array d = Data() d.put_array(False, Data.INT) d.enter() for i in xrange(0,100): d.put_int(i) d.exit() # String array d.put_array(False, Data.STRING) d.enter() for i in ["a", "b", "c"]: d.put_string(i) d.exit() # empty array d.put_array(False, Data.INT) write(d, "arrays") # List - mixed types d = Data() d.put_list() d.enter() d.put_int(32) d.put_string("foo") d.put_bool(True) d.exit() d.put_list() # Empty list write(d, "lists") # Maps d = Data() d.put_map() d.enter() for k,v in {"one":1, "two":2, "three":3}.items(): d.put_string(k) d.put_int(v) d.exit() d.put_map() d.enter() for k,v in {1:"one", 2:"two", 3:"three"}.items(): d.put_int(k) d.put_string(v) d.exit() d.put_map() # Empty map write(d, "maps") return 0 if __name__ == "__main__": sys.exit(main(sys.argv)) qpid-proton-0.14.0/tests/python/proton_tests/0000755000175000017500000000000012770711161020553 5ustar danieldanielqpid-proton-0.14.0/tests/python/proton_tests/scratch.py0000644000175000017500000000224512770711161022557 0ustar danieldaniel def xxx_test_reopen_on_same_session(self): ssn1 = self.snd.session ssn2 = self.rcv.session self.snd.open() self.rcv.open() self.pump() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.snd.close() self.rcv.close() self.pump() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED print self.snd._link self.snd = ssn1.sender("test-link") print self.snd._link self.rcv = ssn2.receiver("test-link") self.snd.open() self.rcv.open() self.pump() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE class SessionPipelineTest(PeerTest): def xxx_test(self): self.connection.open() self.peer.open() self.pump() ssn = self.connection.session() ssn.open() self.pump() peer_ssn = self.peer.session_head(0) ssn.close() self.pump() peer_ssn.close() self.peer.close() self.pump() qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/0000755000175000017500000000000012770711161022021 5ustar danieldanielqpid-proton-0.14.0/tests/python/proton_tests/ssl_db/bad-server-certificate.pem0000644000175000017500000000225712770711161027044 0ustar danieldanielBag Attributes friendlyName: bad-server localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 34 36 30 34 subject=/CN=127.0.0.1/O=Not Trusted Inc issuer=/CN=127.0.0.1/O=Not Trusted Inc -----BEGIN CERTIFICATE----- MIICujCCAnigAwIBAgIEfWGDZDALBgcqhkjOOAQDBQAwLjESMBAGA1UEAxMJMTI3 LjAuMC4xMRgwFgYDVQQKEw9Ob3QgVHJ1c3RlZCBJbmMwIBcNMTMwMzIwMTU0NzA0 WhgPMjI4NzAxMDIxNTQ3MDRaMC4xEjAQBgNVBAMTCTEyNy4wLjAuMTEYMBYGA1UE ChMPTm90IFRydXN0ZWQgSW5jMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4Ed dRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs 14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208Ue wwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BY HPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+Zx BxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx +2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGATqLV argkIbJ0kfQxODtbtouvBPjA2n7VMbmC+YrKQj/YUOjtW/AtD+9lfFy3aekHAMcS HFYmo3U6rUCF6sFnnesq6eGi5F5oGVWCI1trUMVx6zFx2zMg+47RpbD0K2JEwzUg WJmMgu+ZFvzt76lrlS06K33I260dcbUDECWjKNSjITAfMB0GA1UdDgQWBBTSy0ab MCPY1+u0078oxrvoZYwnAzALBgcqhkjOOAQDBQADLwAwLAIUYOCVrWN5+KrdFD6F HDAMD/MQ7OkCFByiloyK+lFrZI+AYo/xEdbJLqcH -----END CERTIFICATE----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/bad-server-private-key.pem0000644000175000017500000000156312770711161027021 0ustar danieldanielBag Attributes friendlyName: bad-server localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 34 36 30 34 Key Attributes: -----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,AB078D4A74BE8031 iEW6u5kMfaX9SIynirmIQk6EvqrGjl8uhGC5k1UHBoQRnYUy/wrz9Ufcw4JLXXmo 8CoX1JCwo/gvlqV3KSszujgkCvCndhlLoe5PwbhMsSSiruTkt9b70bOHxG5AHp/m sr/0cFgs+O1USt9IVmAXj6+ALndWfOBSVH7J40BTDHCGbizB/QRnAk6+VWW2tQRZ mU2xL1drY7n9bvF4O9faDe5C2C0v1+asswXnJmZnQVsTnA5+kwQok6uLfJjVWt7j WS9ME5nIJSOi/ZkIyr2cr4m4TPbPw/UB+funT1/OKg8iyMyUvjwV3fopjo/9Sz/S Tpt+sjUJelL7VBBkuppiZDHjPQ/g0IAc7+HEbc1or8h15AIiSWxEg/HRUtZqbsgC UyW+5qvKyYrPzZYkkJIeRLwkMEAU1sdmHBVutALc9xUyVR8jXJtXNu3V82NQ7otv pRlLpAs4Fn6SOIKAJvL6YdxgSiZFdta/Ory2VXqopJad+EEPPprf8ndk3Mv38l7M gIMQdZD8hhWaPw8zhXfhfnjz7ejPhtgQznkyzJPIFtbrq2HUZKuKpOBkCFfu/E4s k6PC6aW9pNGQW0PqdKuHPA== -----END DSA PRIVATE KEY----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/bad-server.pkcs120000644000175000017500000000276412770711161025111 0ustar danieldaniel0‚ð0‚ª *†H†÷  ‚›‚—0‚“0‚ø *†H†÷  ‚é‚å0‚á0‚Ý *†H†÷   ‚‚0‚~0( *†H†÷  0Ì£©ÄÆr|ˆ^-¨^±Ao¡4ð‚P^â½¹ƒ˜Š­»èFôØ55¨¿è’ŸL³)WÉù'jˆ3¼}@Ç,Öë?ð÷š4ìRÍž¢ØRu¦Ô1¹q†—ã ’»¿šB¯“ÿê+;:v/ð î¹â…Ïü惷àÎ/¿TêÒ[®è©>Q £D´M8©¯ïýÑü˜«Âä¾!3áž6&·QÜ‘7ʹÚEÒP#:žŽ_ÎB”¬9ãjÛÄè¡„ •U&ò¼Yi·¶áS÷MGúZ0¾,‘ døá,áºîÜ6‰¼õ-W2Ù4#©3M§^®W¯«DÍíô8r¢þzò­¯a Ó`õ+j?ÎîÎU²¡ÐœÈ™©].~1ØiSvч=+ YÜ1ÖƒãôG¢Š²ÈŠíò ²øü{ÃÛ2«oµi°GhúHkËW¿o´ƒ„%HöM\R¶Ê¨Œ´c Ù׌†Á n1H0# *†H†÷  1bad-server0! *†H†÷  1Time 13637944246040‚“ *†H†÷  ‚„0‚€0‚y *†H†÷ 0( *†H†÷  0ÝZLÓ¿LdÐÁWê4›{Úù}V€‚@£ãl¹tVÄМ9¡çâooúî>tPABîíÑœ˜,&9b×Ú¤éð÷’¾8$°ž"Nô«O0ëöMùðñã#u8÷ùQŽgÌ" “e÷Ûvý y<Õ<Ž;F nÛ ú™´Áv¦ÁÖ*,\ؤíAh4ÉÌÌWÔ‹göd)D9ÌVy¬rÄqAìÉÞm=Ûð«’ZŸ¯T™Â·7ƒFÎŽQapÕÔp1*Ç Õ„9¯ÌRô_Z†(¤£»¦J¥È*—T]Š.1Ôþ¤bˆ'Ð#뤙#­@ŽÏJä_aÑ«ÝØÈ\'åþz¥kïZüÅ‚ c>i^¦ŽçŠõ~ù+ªKˆRÞõÀ\Ä}@™_ ºXF&:GÐípS)'YxB´‡%ä”uƒk)8—¡±BĬu$¿<|1GÁmA²ÿˆá£.²{vðFt¡‚pS|ª¶ “úh˜òï\/\ N#¸LØý[\!ÝÄÙÌÕáÓ @šOR×çM±„±DŠtä¯%털zÖ f+ë¿ë]ßÊ-°6‘½ ¯Œóà´fÀ!ŽS ^¶[ú× kçz™QršiKæY&†É‰Ý½Núý) _­Ú!ô ’¤oѨy2¡§i)Ía¡ Y*úÍžšèhËïyR4Gr°vv¹ »q‚‘æD¿üWùÔ2LBˆ[{Þr¸øôît™Z"¼¦¬¹&ú X¦AJ¡ŸžhW4Òf»(sÿvþ8å0ÇFâ~\ÎݨÂJˆjÜ«g<äõîÊ8«oWžÿÔýHUËX;cÖƒ35skHI 7M38Æ’–Ðô¾³+EÓŸ@oÆÜT‰XÑá*Í#3ßcÞknd±TM÷Oo±®ÞÝ«j….M¢Š -Îì¾È­+îKÎk6™0[]¹20”µ^:÷ºwß±°jaY«—‹§Y¢†ž ÝHÕp4È–NÙö²Å#l¥:WµF¢”£ÙgQëïVÜÃD^Ò‘€ ¸4WË.{ [çpþOdtŒn“ÈùöÁ&†•S:+`"·Œ¤|:º±ž™ÉW(´3ðèe^‚ÓÈ1Ö¹<‰¶§0=0!0 +0{t4YÀ•ŽäуŸhÆŒÕU'šæöö>ëDÑÛá0’[±b9qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/ca-certificate.pem0000644000175000017500000000227112770711161025371 0ustar danieldanielBag Attributes friendlyName: ca localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 31 39 32 35 subject=/CN=Trusted.CA.com/O=Trust Me Inc. issuer=/CN=Trusted.CA.com/O=Trust Me Inc. -----BEGIN CERTIFICATE----- MIICwTCCAn+gAwIBAgIEe/AadjALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1 c3RlZC5DQS5jb20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTMwMzIwMTU0 NzAxWhgPMjI4NzAxMDIxNTQ3MDFaMDExFzAVBgNVBAMTDlRydXN0ZWQuQ0EuY29t MRYwFAYDVQQKEw1UcnVzdCBNZSBJbmMuMIIBuDCCASwGByqGSM44BAEwggEfAoGB AP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6 MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E +4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmC ouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeO utRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/ C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYUA AoGBAOAw2uKAz6k56DRzZBjSJ/W8OfYg6LV64IliFhE93hhseHF7iOaCycuVocQA fJVO0DDtssf0CM3uCxPNiEbDrdfUu75BCvX6h/CT/Qzgf+eLldJSHtAJjU1zSxN+ GtIBB8cQhCdh5sQL6sEJYgOiIxdW1jKf3/n0MuD6qTXi/9f1oyEwHzAdBgNVHQ4E FgQUqxC+jvigfpiR6M3fb6XppgGxFJYwCwYHKoZIzjgEAwUAAy8AMCwCFD2ikCZi 8V4H+LuqCBD4Vz0ug0ntAhQ4kE+VGY7YK++kDZ8jHcfyDUNVAw== -----END CERTIFICATE----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/ca.pkcs120000644000175000017500000000273412770711161023437 0ustar danieldaniel0‚Ø0‚’ *†H†÷  ‚ƒ‚0‚{0‚è *†H†÷  ‚Ù‚Õ0‚Ñ0‚Í *†H†÷   ‚‚0‚~0( *†H†÷  0póqÚ“Ç¢iÍ©»áÆ>- ’ׂPjÁî4àßÈlÕƒ‰¸Ð¸F,t›a˜ «ä³)]MÌÒS2ìKGcz9ð ’º7N¬Ú\Tž1(Òà*—nÞ÷ü¹°`¦Ôˆü+ ËÆ pÒº’/akp"EO:,ó…\»—Ód¨\õy´‡Æ5{ÜÌ%qÊÍÓUO‡µc‚þ;ñ­Û”˜¿Òž%¸›¢¯ö߆:#nÑ¢uÒ§ v¿ ¸ûΫâµ}ªQ”FÄ/­ÕF˜¬®¹ílb¾Û³‰·WWsb„“cAh«0³@·Áj;Yꉉ‚GšE²fG<ZÄÎI­%xäl{ƒÃ`jhý|%C:Q€ ÉyR¨ª8Éã’‚ÇÃv›ýLÎ" I{‰¼'É«¢Q´TÀNù °\(06nÏD™õbHöž~á?ʈlòÝ;Ñ7»>€ÄÎÖLÏJ¯õhôAÎh180 *†H†÷  1ca0! *†H†÷  1Time 13637944219250‚‹ *†H†÷  ‚|0‚x0‚q *†H†÷ 0( *†H†÷  0)Cšæb F0VŸŸÙ;‚m5Šý€‚8E™ØgœŸø¸C>5B¢ލ†ßü¨_<±Ä×yùe¬UªÖ `ˆ:%ú?'’gŽ —é8ؽÝá]"nŽðsïÇæNåîÛ…šn¿á"VdŸØ]xÜmFËåU˜ím|¼¿;ŽÌliÌ*%º“ìÁçù3‰ÐAÔüªÞË-U4=w,´£¯wÖ·0ªð¥†ÕxãËä£Z£ýŠTÕÞDÍg‡ZörÕ#“²Nð Mµ„ÌåÊ|›ò­å»u”Œ™i±JÆð¸Œ±¹éà57~&ߢaÞ«»-ª*7^;ä—mžÒW¨.6Å_¸Úf²k±ã 4à¥UÍê/…ó“~-jÀ'–&[ù«sWƒÑßÃ;ââÁz^uT޲rv£ÅóE öÉ4 Ã÷< îÖé©VpMÅŃEÞyÄÑ(;/ÕWõ%^°ø%¢Ì+?ÃúüÉ NÃ¥  ‡g7ìíqý.›µmC°Ìë’Bª`_N'ºS,åûùÒ”ãûhËžjëO’«N‰:4™Åayšö¯-QZØ›³a4Ò%5qî2/˜”íŸÈSi¿-ðÆÂd\x!ñ,>ð@"2¦Œ\,NÍR±†³ë[ÁÔ/¥/H?I–2¨ÿQþŒê©š£CÑ26”Ù®òÝ•j¤t ûV}F§g\îŸèãÒÜ@Û¹žÜ @¦?UQ0Ð3-±d+í‹n¼ùói77IÅ…ˆ^p¬„á=#…è„äzߥ4·.µ—´;ë¸Ykòosªt›ê¬]ö"MÌ?g8„?ØìªQ™õNqÞy ¯g(½&P¥L&Ü Áaÿ¬6wþ”©Š8kœXu)‘¾¼¿å¨Ž¨“ûwÄÛ•f.¦ìÔÔßSi³’íËÂHdÍ”§Î«eÄ+ 4ë"ìJed/åâÂ4V§ó~üò’sø$Š-Kœ&P®µªÊÐôG¯F0=0!0 +“‰£™g¢Ž¢W6‡¤ì1"ñ\üY§·©®Eî«Êš\<;룺S«Äqpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-certificate.pem0000644000175000017500000000202312770711161026257 0ustar danieldaniel-----BEGIN CERTIFICATE----- MIIC2DCCApSgAwIBAgIETM/4+TALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTMwMzIwMTU0NzA0WhgPMjI4NzAxMDIxNTQ3 MDRaMCUxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0GA1UEChMGQ2xpZW50MIIBuDCCASwGByqGSM44 BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6 MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P208UewwI1 VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA9+Gghdab Pd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim 4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKLZl6Ae1Ul ZAFMO/7PSSoDgYUAAoGBAPYvFAX9tcVv9T+rsbF3pD3++ji8PD6sPFmH5RQ8RyZXDzs5jdku4AVb BtmLp+swmQ/NnQRvoR6lLvfB5gOzykPU/LrtEELEbp1ScXqNwTQky2OkX7+YGSKnliWZm5v72rtt gGL9j+c/jKcDAj7Z+v2kHugbTuZ09AxXLQ9cPxWxo0IwQDAdBgNVHQ4EFgQUaLUIuA06KCstRynf 6L6X8+A+/ygwHwYDVR0jBBgwFoAUqxC+jvigfpiR6M3fb6XppgGxFJYwCwYHKoZIzjgEAwUAAzEA MC4CFQCWcpy1LVRqK+Udtq4qCpIKDZwTdwIVAJS+GitAJeY2L1ltlgi+cpRLIgGU -----END CERTIFICATE----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-private-key.pem0000644000175000017500000000160312770711161026240 0ustar danieldanielBag Attributes friendlyName: client-certificate localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 33 34 36 33 Key Attributes: -----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,357362201C460FE9 L7ubHRpBWVYpCicB5srjF7AFpTDN/faMbz9FuvFmA/8HBhwOrlbKau0ASoDqvGbq Gcx4BqXvNx22gJbu4S8224elyov7beI58VQ4/k1kJROa7Gyi84RpqxmdScCaYrNE 2beGa+AshN2vgwtRzeUDHxjKj/vPlDjdBq3cT88W7zrfm7J2E4HuNtwTwQ+EhBh9 c5P+yxOmF93AxQzywGQPkmhXfhSHkoUWX/7NNtdhL07m4CY8nWwrGfHm828/d20Y eaGhyuxiC9hN5mhSct0THIyLSTz6fm7sJLZzDM1poqEKVdZQyytfUkpzCjDik3em y1Pjymve8QcrWEN4SLO7V7J8Zkv2N9AjJt/XiZWAdn13Gj+qLs/DI//AtlthqntJ qH0rZeV0DPf6tKZmj3sTegOdmvv8hAVX/DkEwC9wkxhKU7xHmBzX+uMqIauL70GH F4w9dVGOCSFNFP3bwoDCotJbLHx/vMpu/1AMibXUnPVQkZaWf3xlmz7ufJZh3Vhq buAuLw6t2ji8wnpOfOOB9hm2cGBcPlw2s3AHiM66vhLgOvtKQbGxMTni6g/kya5u BuWOjFk54PyY1DM54VK0FHoBxcvMmLo5 -----END DSA PRIVATE KEY----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-request.pem0000644000175000017500000000160112770711161025466 0ustar danieldaniel-----BEGIN NEW CERTIFICATE REQUEST----- MIICWjCCAhgCAQAwJTESMBAGA1UEAxMJMTI3LjAuMC4xMQ8wDQYDVQQKEwZDbGllbnQwggG4MIIB LAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAiUftZ PY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYVDwT7 g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc9QKB gQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPoTCgW E7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa5Z8G kotmXoB7VSVkAUw7/s9JKgOBhQACgYEA9i8UBf21xW/1P6uxsXekPf76OLw8Pqw8WYflFDxHJlcP OzmN2S7gBVsG2Yun6zCZD82dBG+hHqUu98HmA7PKQ9T8uu0QQsRunVJxeo3BNCTLY6Rfv5gZIqeW JZmbm/vau22AYv2P5z+MpwMCPtn6/aQe6BtO5nT0DFctD1w/FbGgMDAuBgkqhkiG9w0BCQ4xITAf MB0GA1UdDgQWBBRotQi4DTooKy1HKd/ovpfz4D7/KDALBgcqhkjOOAQDBQADLwAwLAIUWRqolXje 1mMzoode9hn5ngboHpsCFBIGJt8s5WYcW3j4JVCaoqUypJB/ -----END NEW CERTIFICATE REQUEST----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-certificate.pem0000644000175000017500000000205012770711161026307 0ustar danieldaniel-----BEGIN CERTIFICATE----- MIIC5TCCAqOgAwIBAgIEGK67vDALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTMwMzIwMTU0NzAzWhgPMjI4NzAxMDIxNTQ3 MDNaMDUxIjAgBgNVBAMTGUExLkdvb2QuU2VydmVyLmRvbWFpbi5jb20xDzANBgNVBAoTBlNlcnZl cjCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEm aUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX 58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLr hAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0 SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJ qIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgGd51fWwKIVM6wIsVk0vo86Hq3q2gxlP0STl /EzEBew9buSMXPCqQvQIhw/Ud6/f/Q0KxctPn8MqO++jCCSYMYH5d1ME85X9QM2mh4/xejYWQdUl qJKkHPo6MbLgEfQY7UxXxMq9Ekij/T6MyS1Rd9xwCCf2wJhjV6Jq35KplnWMo0IwQDAdBgNVHQ4E FgQUlZgov7xbp4kcuwMI7d7AAz4DH8YwHwYDVR0jBBgwFoAUqxC+jvigfpiR6M3fb6XppgGxFJYw CwYHKoZIzjgEAwUAAy8AMCwCFBTG8MXcRKCTW6gBKIjp23BGWJfIAhRLFMZ4oYLsdCImFOl7/Hi3 NdK9cw== -----END CERTIFICATE----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-private-key.pem0000644000175000017500000000157312770711161026276 0ustar danieldanielBag Attributes friendlyName: server-certificate localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 32 33 34 35 Key Attributes: -----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,58EA06E340D4B8FB cYo9OeXX1j8HazOZUVLCLaA5hbVd92OY5JufYXXzJsyfoBSWsH2IPIWw6oolJfD/ Nd53xpl3gW5AuVk6gZkfV/qUQeymTJPtQUPjfgEEK50s7PCj5GKNL63/SOVVYudc HOczB9wb5VrVstKBdPe5SkxtOoMGka76uXDAaApezpHcwxFKyzmixevc8f7/3Q7q 02TCaufgzAKYzO9sjY/U8nR0qvn1Cnx/AO8Lwt0K3mEExqCR0R7yyW1GwRRiMdDe x7QnYosHScSao7f1ToMLYPGdtMSUWBt1m10hrcPaCzvH5Zqy7w+wqQp5mG8dHp7o v767dWezeY1k8RpKiTZHlKZCksfqWr3TSgICOcFZrrQbxsCjIlpSW+65uhrDtUN1 CqJmTzeUeRFBKGGdBMe+I1gUxsVohHyQzxyxUMwmu3fQQipSsvEyjq2O3CxaoPyi bbvbmvhdHGhjOQXeSJpZ8QsKRCUbeQQbaEzD6cGZv/VVzgYZfbEFz3xAb+nqVeKA JftTQeful80+cpUNalFMY7ozhbXznLwKGB4X5EnC5COLhJJdXOTEx9F0ASwvdi1p hvNdZ1wiRQvyvLyhvI2wQw== -----END DSA PRIVATE KEY----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-request.pem0000644000175000017500000000163112770711161025521 0ustar danieldaniel-----BEGIN NEW CERTIFICATE REQUEST----- MIICajCCAicCAQAwNTEiMCAGA1UEAxMZQTEuR29vZC5TZXJ2ZXIuZG9tYWluLmNvbTEPMA0GA1UE ChMGU2VydmVyMIIBtzCCASwGByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9E AMMeP4C2USZpRV1AIlH7WT2NWPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up 1/63xhv4O1fnxqimFQ8E+4P208UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUj C8yykrmCouuEC/BYHPUCgYEA9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZ T+ZxBxCBgLRJFnEj6EwoFhO3zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7 zKTxvqhRkImog9/hWuWfBpKLZl6Ae1UlZAFMO/7PSSoDgYQAAoGAZ3nV9bAohUzrAixWTS+jzoer eraDGU/RJOX8TMQF7D1u5Ixc8KpC9AiHD9R3r9/9DQrFy0+fwyo776MIJJgxgfl3UwTzlf1AzaaH j/F6NhZB1SWokqQc+joxsuAR9BjtTFfEyr0SSKP9PozJLVF33HAIJ/bAmGNXomrfkqmWdYygMDAu BgkqhkiG9w0BCQ4xITAfMB0GA1UdDgQWBBSVmCi/vFuniRy7Awjt3sADPgMfxjALBgcqhkjOOAQD BQADMAAwLQIUH7G2vQMVP1JURjsKcruCMMN2Nv8CFQCL3mjZX5zQE68aBdaL6163zvWMSQ== -----END NEW CERTIFICATE REQUEST----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-wc-certificate.pem0000644000175000017500000000215012770711161026717 0ustar danieldaniel-----BEGIN CERTIFICATE----- MIIDFTCCAtOgAwIBAgIEeHbOXTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTMwMzIwMTU0NzA1WhgPMjI4NzAxMDIxNTQ3 MDVaMDAxHTAbBgNVBAMMFCoucHJlZml4Ki5kb21haW4uY29tMQ8wDQYDVQQKEwZTZXJ2ZXIwggG3 MIIBLAYHKoZIzjgEATCCAR8CgYEA/X9TgR11EilS30qcLuzk5/YRt1I870QAwx4/gLZRJmlFXUAi UftZPY1Y+r/F9bow9subVWzXgTuAHTRv8mZgt2uZUKWkn5/oBHsQIsJPu6nX/rfGG/g7V+fGqKYV DwT7g/bTxR7DAjVUE1oWkTL2dfOuK2HXKu/yIgMZndFIAccCFQCXYFCPFSMLzLKSuYKi64QL8Fgc 9QKBgQD34aCF1ps93su8q1w2uFe5eZSvu/o66oL5V0wLPQeCZ1FZV4661FlP5nEHEIGAtEkWcSPo TCgWE7fPCTKMyKbhPBZ6i1R8jSjgo64eK7OmdZFuo38L+iE1YvH7YnoBJDvMpPG+qFGQiaiD3+Fa 5Z8GkotmXoB7VSVkAUw7/s9JKgOBhAACgYB4enGCtdRSyyqTJ+q7oZCHyjB/2QdvIKMZrca0bNbk iVL0VT03aQ5XlzRCYPMBFwX8V4ap5XKmCj3GDVDA6cat1I0a4PWJmU2Mgv1jCgktrRghq+9dv+8i 949cZf6FvMcA+CECkcR1t+V2dobQRwfhBgeql2TtUkuNRmknXplQ0aN3MHUwHQYDVR0OBBYEFPXv b/vh+yyp38bf6eodkSFKXRKxMB8GA1UdIwQYMBaAFKsQvo74oH6YkejN32+l6aYBsRSWMDMGA1Ud EQQsMCqCFmFsdGVybmF0ZS5uYW1lLm9uZS5jb22CEGFub3RoZXIubmFtZS5jb20wCwYHKoZIzjgE AwUAAy8AMCwCFFKqHg73AIZ9lsNClefQQqUqMp4/AhQjpVnd799wousXAvTtYNlH/7kWFA== -----END CERTIFICATE----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-wc-private-key.pem0000644000175000017500000000340112770711161026675 0ustar danieldanielBag Attributes friendlyName: server-wc-certificate localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 35 30 32 32 Key Attributes: -----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,4AA7362A0A1CE3D0 sLqxs1MtHOj0O0sO2YUSQMrsvl19KBlabPwiLhrLKPMzyK8Xad4S8V6J9U4QZl3I n6vY7XvLPx+OqPE9X6vuRfErzDzzjkrL3/4+VTj+bFdetR85ysg1iOVnM2B3MhxW qF9TeOpxOWokN8ck5X6TYuo1V6NcYO0rZ+oTcqe7nNdmJruwHf6dgWPeLRhyT7Cj IoidnCiTYKCIVH+3Hu30ZhnF81hE+vXt2EtN78kUNojlsSSsxmzOXIaPGwVRYMzw QqhKcX08Uo+1gHfcNfvjDpWyybBo0oznEneGvxxGoACC3KIJMAf6CB0ToP4JnSO9 GuNj51k2M47MdCOlkvWD6OvwMNU+qtfFo02cHj2ZyjSYTry0/XnBSKfdMs8Yz0Xw GxsWY7f2041XBqP1gXUbjLygpNzNoD4jyxoPbgPequsCnSl6x+dORc7HICJ4VXFk 9DCk0Xu+22PMuMl3i743SjOoxGntJCzQfJABbo6txbXbLnHrByRHgZyPeIBNrQZY fZm1BXRexrnXMiKyVhl0rgZaIlVwxW8yq76mRv3E+srYncWaPzPvI2UoNGJI6kqv TfQP2IYr3QQ4FsN70rZAe1kdur8qmo10 -----END DSA PRIVATE KEY----- Bag Attributes friendlyName: server-certificate localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 32 33 34 35 Key Attributes: -----BEGIN DSA PRIVATE KEY----- Proc-Type: 4,ENCRYPTED DEK-Info: DES-EDE3-CBC,2EC922782CE1727C fsM0zmhcMgj70OG+cX5FFIbS1dVFZDVpqUFXASlVzYgx5t8nTISPSBA9mQup34MG 28sv2zxLdb+bXFuzkuq3mzuj3NLZizo7o6wRuUpbpbmp6hR6K5fkfu7GsPXCl380 EjbrUCdt2iDiDJLyNT9Pu3ngdx3tOqz8JE3oD93FAfVZDKlzigfmX1sS+qOyqrCO JbRqaCJOQ5F+g73QvM9cOQLw1F/n9FqtPFNSy+Q0LFBcxfznsTk4pnPFJEko/2F0 r9fudQS0vouNgZ4i1OzrQnWTzVeqVoSaa6AywCrynpiSWBfxMIbT78zjyoUBD47H nlGjMdtpoo6Xmd3CjY/pHc7Gi4RiTvBR225V/djdZpIDp7Hoyp2jMSWmsamCEFMj aEx7VJQtAEIyrVsCbYfvY6pE0id9dQOZSZnBtn8sHqy9DMfd6bR8FFQx48yXzO8H sxBNOFjkNjnjm3YWTm5q6iQ0LTke+EplixN2J1wjKz16Iy/36zCd+2rks2KXIXXX 4dHTDPvV+9WKrfmk2ZQx/j2XQfPt34a0TIERJ5zAJuHH7a9zSCX0j4k7XRCI2GOQ Mu7wsBLassVgVCPF3J0Flw== -----END DSA PRIVATE KEY----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-wc-request.pem0000644000175000017500000000172612770711161026135 0ustar danieldaniel-----BEGIN NEW CERTIFICATE REQUEST----- MIICmTCCAlcCAQAwMDEdMBsGA1UEAwwUKi5wcmVmaXgqLmRvbWFpbi5jb20xDzANBgNVBAoTBlNl cnZlcjCCAbcwggEsBgcqhkjOOAQBMIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+A tlEmaUVdQCJR+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb +DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5 gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQ gYC0SRZxI+hMKBYTt88JMozIpuE8FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6o UZCJqIPf4VrlnwaSi2ZegHtVJWQBTDv+z0kqA4GEAAKBgHh6cYK11FLLKpMn6ruhkIfKMH/ZB28g oxmtxrRs1uSJUvRVPTdpDleXNEJg8wEXBfxXhqnlcqYKPcYNUMDpxq3UjRrg9YmZTYyC/WMKCS2t GCGr712/7yL3j1xl/oW8xwD4IQKRxHW35XZ2htBHB+EGB6qXZO1SS41GaSdemVDRoGUwYwYJKoZI hvcNAQkOMVYwVDAdBgNVHQ4EFgQU9e9v++H7LKnfxt/p6h2RIUpdErEwMwYDVR0RBCwwKoIWYWx0 ZXJuYXRlLm5hbWUub25lLmNvbYIQYW5vdGhlci5uYW1lLmNvbTALBgcqhkjOOAQDBQADLwAwLAIU HwrrI5XVNNTolSMnuOEQ2uhE3lwCFEASAlVD+LyszXTiFF/8zOgbRy/Z -----END NEW CERTIFICATE REQUEST----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server.pkcs120000644000175000017500000000564312770711161024364 0ustar danieldaniel0‚ Ÿ0‚ Y *†H†÷  ‚ J‚ F0‚ B0‚ *†H†÷  ‚ø‚ô0‚ð0‚û *†H†÷   ‚Š0‚†0( *†H†÷  0Öž­èm»škQQµÛ]‡K»:‚XÝ šøákî¿ÌèÏ|Õ¾Ì%½eÚ€UîáñQ·ìcet™½z¢Û 1߉ÍòòêÜ7¤€E+B…¸òÙ¶|¥öPtÆ–zNnüþ¦§äîølõÈ‹µš„0g2[k“æ‘Zž¡§îÕ $¹ü.Õ/ijÿV-ƒÌV•À{U¨Öõ‚Wq§FÇQœb™ä5—çàÉó¶YŸÎ†V’Ý*êÚ‚ wz•Jjõ°‚¸ô¨4%IÕÄ0*¥0R]e]鉋×-™ËºÑø.¯˜.î›cÂü6åGf«L–s;r¢IN‘FúÅëQ=šuætùóòS/tÈßd+øã‰`×bÝ\ÿ›~àVÜcM¾7CÌ#Âr*P¼í1‚^@—ö¤a‹fÀßâ¾ÎB—Üø] C“ÐlÍm0æFNM åó÷½ a¤É®ÓD©Ä"/Ç÷⤠ò%h/91^09 *†H†÷  1,*server-wc-certificate0! *†H†÷  1Time 13637944250220‚í *†H†÷   ‚‚0‚~0( *†H†÷  0„îL…‹PÖ›(S½ð¦´¦Š‚P|T£„Rp mîÿ‹ª¦Íj«ê^lö¹¬™M쳴푌úR¿ÙópÁ„[E†ÇZñ:¨ñM¡á2F#Cœï˜,ËzV³T«=ðú]•ÑÕ¤ÁݤŒ¤Â+(ô—VôËjßÞ`P…ëK«ä`XSvqÝW*÷@…mJ,ËäƒSÆU¤0ᮇÍ.'Ûæ+>  &’ƒí<êm=ÝÁ F„ýq¡7•ç&ѽ×úAb= 50&»¯ªg½Ê /÷ŠÍñ̳ÉbQ6#qòdŸ9SάòH)b¸i–Ç;UŸ2Z>ÏAà0¹‰ÖÍ™zlšßVܬtÖÑÙ¦[‚@W3 9œwR’»$àm–ƒ¯÷`¹ä2ÑòqÐ&áe^ï¿÷ ͧ0áe0+iy»›rª§ºç>@a=|Ú¿Q°@½M/1X03 *†H†÷  1&$server-certificate0! *†H†÷  1Time 13637944223450‚3 *†H†÷  ‚$0‚ 0‚ *†H†÷ 0( *†H†÷  09³~Q¢PÖBAn×¾rxBª–€‚à;K1)\ÆXî÷žŒñgÇ<ºžØO ÌÆ×|‚*ÂÞ˜2ºêD¿Ö(HàÔJ¥ä§Ü¼]·>sGà-4Y°­Æëªâ·L>E0¬.Q€Žß\Œ}r”kÑÕ<óÁS]`åzÒl½XŒyœP¦Î•+Ý ªZÙö¢e±}[Pö«Œ¤Óð'X9gêP63µFP9tîBžY3ðئ.Tƒ¢®„ÔaR£ùl#’ÔÚÐæUy 黯 ¯jáI U[ͯ<&á9€lõs*5¼£ Â{AŽÙê:ô°O›~XŒ£X j‹—£u›Gþ3AðW8Ñhë„+ˆüh[: T`:{¯Ãͱ‹rÔ J KŠtšû vì/έ³‰Ì™‡¸@ï J~XŠ©Q½Ùà+„Ãjˆ]†¨¥ÚÜTjæ‰ ››MÚD¶:n¹Gå†úŽN¶Ýüíÿ6_÷7œô¢Ó¡†AÙT¸š­÷®Íµ°+p쮥¯…óüÙâ^p$C|f4vÿúTÜ”dH¡Ç˹tð!~õ®äl*[%‘-ƒÿKê”t<%Fß»;ãq÷Êö(ú¨ENyc$àÇ#ð;\zgCŠqâUoõaÃrâœj$óÐ’¾ø†¥ÆÕHhÐŽ¹LžÊ¶©míÙŽSÄ©žqô„þÆK5½„"W§ã:¿´l@ó,ZÊn“¼LáÕ!n¦äÞûò±÷÷âP•Œ`éH³ú ÊêO&×ßzÝìõ¶v8ì‰Þ*•™ÿgxÝD M¯3Z»_³J1iO[Œ6^ZÅȨN(ý”*ó#ÓºfÙÈ59‹ ´ÿ= w¨'ÎI_‚EK¼@Ìæ}³œ’=^=¨B©3Åoltl0¿2ýó\Ùnå¾^!ÂG=Ö+`Ï[ׇþ>ß°î“ ËG® 94‹F£Å@RL‰ Ó’%kÆu×bC89R«·`_»{ }«Û/HAPóÆ`åhû·2œ‘¾G3%#gcqñJû•þ& mäàRÛ<ÈΰnØbÚ‰‡wò_ßQ Ê Ô?•ð×~Z­$Ze˜4_ôë*#e‹ëG[a Û¨¼:KEµÜX!E Ä KÔìlÐtõ¯´Bd“B]«y*È‹­h$Útš’‹“sXâFõ¶gEÙG¢j{‘Ü{_"ÛçD$´Stu‡kˆweŸ˜¹ÔÂ?©š›­Lè$¢²+¢ÿ¯¡Rói5i¨Áâ¯ñÀè¨n ÖȽ››šnábgXuÑEs~"ÕiÔ-ÁîÔ—ù%;22~#|²%nùñ”‡ï>—'iXÙ¯_7T0=0!0 +~D?ýüyƒ{lõÃõ.´a¬®3‚§[k%FEäŒGÍ1>^qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/README.txt0000644000175000017500000001577412770711161023535 0ustar danieldanielThe following certificate files are used by the SSL unit tests (ssl.py): ca-certificate.pem - contains the public certificate identifying a "trusted" Certificate Authority. This certificate is used to sign the certificates that identify the SSL servers and clients run by the tests. client-certificate.pem - the public certificate used to identify the client. Signed by the CA. client-private-key.pem - encrypted key used to create client-certificate.pem. Password is "client-password" server-certificate.pem - the public certificate used to identify the server. Signed by the CA. The CommonName is "A1.Good.Server.domain.com", and is checked by some unit tests. server-private-key.pem - encrypted key used to create server-certificate.pem. Password is "server-password" bad-server-certificate.pem, bad-server-private-key.pem - a certificate/key that is not trusted by the client, for negative test. server-wc-certificate.pem and server-wc-private-key.pem - similar to server-certificate.pem and server-private-key.pem, but contains Subject Alternate Name entries, and a wildcard CommonName. Used for certificate name checking tests. These certificates have been created using the OpenSSL tool. The following bash script can be used to create these certificates (requires keytool from Java 1.7, and openssl): --8<-- #!/bin/bash #set -x rm -f *.pem *.pkcs12 # Create a self-signed certificate for the CA, and a private key to sign certificate requests: keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -genkey -dname "O=Trust Me Inc.,CN=Trusted.CA.com" -validity 99999 openssl pkcs12 -nokeys -passin pass:ca-password -in ca.pkcs12 -passout pass:ca-password -out ca-certificate.pem # Create a certificate request for the server certificate. Use the CA's certificate to sign it: keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-certificate -keypass server-password -genkey -dname "O=Server,CN=A1.Good.Server.domain.com" -validity 99999 keytool -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-certificate -keypass server-password -certreq -file server-request.pem keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-request.pem -outfile server-certificate.pem openssl pkcs12 -nocerts -passin pass:server-password -in server.pkcs12 -passout pass:server-password -out server-private-key.pem # Create a certificate request for the client certificate. Use the CA's certificate to sign it: keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -genkey -dname "O=Client,CN=127.0.0.1" -validity 99999 keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate -keypass client-password -certreq -file client-request.pem keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request.pem -outfile client-certificate.pem openssl pkcs12 -nocerts -passin pass:client-password -in client.pkcs12 -passout pass:client-password -out client-private-key.pem # Create another client certificate with a different subject line keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -genkey -dname "O=Client,CN=127.0.0.1,C=US,ST=ST,L=City,OU=Dev" -validity 99999 keytool -storetype pkcs12 -keystore client.pkcs12 -storepass client-password -alias client-certificate1 -keypass client-password -certreq -file client-request1.pem keytool -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile client-request1.pem -outfile client-certificate1.pem openssl pkcs12 -nocerts -passin pass:client-password -in client.pkcs12 -passout pass:client-password -out client-private-key1.pem # Create a "bad" certificate - not signed by a trusted authority keytool -storetype pkcs12 -keystore bad-server.pkcs12 -storepass server-password -alias bad-server -keypass server-password -genkey -dname "O=Not Trusted Inc,CN=127.0.0.1" -validity 99999 openssl pkcs12 -nocerts -passin pass:server-password -in bad-server.pkcs12 -passout pass:server-password -out bad-server-private-key.pem openssl pkcs12 -nokeys -passin pass:server-password -in bad-server.pkcs12 -passout pass:server-password -out bad-server-certificate.pem # Create a server certificate with several alternate names, including a wildcarded common name: keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-wc-certificate -keypass server-password -genkeypair -dname "O=Server,CN=*.prefix*.domain.com" -validity 99999 keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore server.pkcs12 -storepass server-password -alias server-wc-certificate -keypass server-password -certreq -file server-wc-request.pem keytool -ext san=dns:alternate.name.one.com,dns:another.name.com -storetype pkcs12 -keystore ca.pkcs12 -storepass ca-password -alias ca -keypass ca-password -gencert -rfc -validity 99999 -infile server-wc-request.pem -outfile server-wc-certificate.pem openssl pkcs12 -nocerts -passin pass:server-password -in server.pkcs12 -passout pass:server-password -out server-wc-private-key.pem # Create pkcs12 versions of the above certificates (for Windows SChannel) # The CA certificate store/DB is created without public keys. # Give the "p12" files the same base name so the tests can just change the extension to switch between platforms. # These certificates might work for OpenSSL <-> SChannel interop tests, but note that the DH cypher suite # overlap is poor between platforms especially for older Windows versions. RSA certificates are better for # interop (or PFS-friendly certificates on newer platforms). openssl pkcs12 -export -out ca-certificate.p12 -in ca-certificate.pem -name ca-certificate -nokeys -passout pass: openssl pkcs12 -export -out server-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey server-private-key.pem -in server-certificate.pem -name server-certificate openssl pkcs12 -export -out client-certificate.p12 -passin pass:client-password -passout pass:client-password -inkey client-private-key.pem -in client-certificate.pem -name client-certificate openssl pkcs12 -export -out client-certificate1.p12 -passin pass:client-password -passout pass:client-password -inkey client-private-key1.pem -in client-certificate1.pem -name client-certificate1 openssl pkcs12 -export -out bad-server-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey bad-server-private-key.pem -in bad-server-certificate.pem -name bad-server openssl pkcs12 -export -out server-wc-certificate.p12 -passin pass:server-password -passout pass:server-password -inkey server-wc-private-key.pem -in server-wc-certificate.pem -name server-wc-certificate qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/bad-server-certificate.p120000644000175000017500000000272212770711161026662 0ustar danieldaniel0‚Î0‚” *†H†÷  ‚…‚0‚}0‚‡ *†H†÷  ‚x0‚t0‚m *†H†÷ 0 *†H†÷  0Å›Mϧ3€‚@dŽlI< a ¨>É+’u.¶²j6§:+º%°¡ɇ[©?üIÖÞÆ¶Ëhñ@3ouš_ŒMÊÙ“²?™Ïñ*-q¯I#a%Þd‘Jk²¾ yŒ^Œ× Ym¥Á‘0Úà˜©Ž žqº˜†Ž^|€“iªVÎì Æ !óýšµp§hËz:ºÚþúÂß ÊãUÜû”àIr…± ðær$³TÂÐ͆)qóŒ2Ÿ1A—{…LÚP1ÿ#žJÖ4ˆ‘€¢úíNÛ@K 9Žÿ9&·ÌéÌUž$NFï6Ñ€ÅK"FC“}s“@S£¢å#òïÿ ƒh0Òt³2¿tÖôìf™Ÿ¥ÌßÜr 1!x‘“†;LC¾x¤'ŸÌTR¦-²ï9âr9¤Ììe6‡WM팜­h+<šKÖh+|CåS›‰ÓM9"ôÞÝ'ëd:?»£Ê0,ůkã‘ÑåÍhݧr‹W\/› ö­Ò†ù לO7ؼéˆs¨ r€^¬Ù¢×Qªïù2Ѻ ‰ÊM}š{ÚÂߨ*“§Ã·ú7"K´Îƒ…àŸØ ±ì’/…!O¹QbyÚ¨xš®Co³'£~;IS!@.%”'[ª­ÙƒgÇ5ðøÿmâf©œE—5ÿļìmxÛŸ†/TýÙñ0± jú7í×àІ·ÅÞÏÁQ]ïÒ€ O^L¥­\¤›_éÄxR|Ù8ɱû8+ò$mŸùÖð[¤˜QjQÅ…´>ߢÇBZEŸxl£ðÀKµ]x­ØŒg/È9>öQ¡2ˆüªéU³§]à’Ûˆ/ÁþØ€k΄Xþ#¾°Éß ?šÄÓReaÐiDÓõW-Á÷x&×B“ÂU%-_ù¹ûÄl'n õ¸ ÌØUw*a/d^ ŸO™B” Ÿi^ȲžšæýºÅP€®´¹_ø)½\aÙÖçµÞïT öµœ¤ÀKÎI(ZzÆÀ—HÿOã 4=@ÔpqTLyàEj9áÑú&d–èIâµe¢:’ùuzüP Ï.ÆëOÈÙ?%N–DŠ&mî^mO0‚î *†H†÷  ‚ß‚Û0‚×0‚Ó *†H†÷   ‚v0‚r0 *†H†÷  0º‰7¡H.`–‚P¯< ÑèQ9A"»Ñ›¢åósԻNö9Á£h`1)Êdt:Q2sýI|Yj±Ù`»Ž­§¤LGÎ$’­*ÜÁl¼};Û¸&wÄ›ßÇg}RHqANe/d‘×òŸ÷v¶Ìçí£¢;c—ëì©BôÄ„òëÉ>=ë<:#,ÒãA¼d?¬‰ ­ÙTï“»ŒD*"&¸Žd摼\÷-†|ñy3wrPqë—A?À…P¼‘÷ÈáKÞ m l7¸ŽiýìP´Þ=é=È Â5l‘úkÒ~¹¬ýPB”¢’m€«H—}yjiÝ{Ì«"ÖÕzÑhÔíù†³rž{øÞY!’]r,‘eZløöÉ:¥ô}ªwN‚˜ŽªiAé’Gæ)Q[ƒÔa™&A9Î2¿. ÏP„®³£)ºWD¯Ç„b( ÇLwJ˱£CÅ$ç™H''iÕL ÁçÆk÷VPØãçkÌÙòß'éZë|5”E³£º?§494NÛ--ls¸6vØ C`Iûè» 5œ¾‹01µmûÎÓH½ãïW;›ïJ‘sy?ÍG›°í>›L'•÷ʧ… &›ˆöCÎÄÅVÏ­J}Û{Ö¬Öðxäú¦þÙ¾‰0¤X ¸Û…5ÉdŽ+µ!Dº$݉`HO8 ž¤K¯dó$u 2â…*(õñëÓÏûQgƒ|Ö…Û‰ç,¢+tû¾[þ òÛ}vZ5ëìTy2“e/³`µþòƒ?ý¤ôúŸÖÍÌ‚ùÛaS¡ÇØÙ,¿Æ&æê€5TfW¹MC cKƒäÍj´\Ò¹šÉ:5°s1ß±ƒðºü×Áƹ¡O¯,˜â€0ÃîRCmË‘~c̨ÌÁgÇî1»×0'4—ól‹Ù*Kñìu~‹ýÌû«¦',émI˜™LO™u5‘F¶‚H„¹žr»¯‰¯Hˆœ`¦Ø¨x<:(4F‡z7ËZ˜?”q·4P‚kõðsË2&ZU¬ï{[n=lvßcU¤HmØ#ì60ídÚ…ó\HÓÅ>MÔÛcÿ×8-†4já25t·dD‹Î»PVH•.‰™eöÄÝÿãöV¦äE7¡êé~TßPÔoŠ#ª pÑsÍ3ý@:£Ê}T–ÍNU€ÓÍ4Ig&‰Ô´òÙ9ù ´ï.ÆÃÚIÃ$ûB8ÌŽ èr{˜"!GXR™ciwL°kÁ"èqã»\÷ú´€ºÿª¨Cùe¬ga…ÙVØ™9r_o\”ºÆ©·iÂèñ$ßjqTßG`yÝî010!0 +_’ñ'œB ²¹ã‘d ð¡òG&æh¶å«nƒqpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-certificate.p120000644000175000017500000000302212770711161026100 0ustar danieldaniel0‚0‚Ô *†H†÷  ‚Å‚Á0‚½0‚· *†H†÷  ‚¨0‚¤0‚ *†H†÷ 0 *†H†÷  0à WF Kzš€‚p]a'qé…º+Ôe)J¶¶[‹‹e€¯=ò:Y#°jìGõ$1Ê¿ø•2cø_¼ÜŠ„Û.)=J\J*‚= äð¼Ž}=&1ãàGrÕÆÌÚl¿\]T¯bgÉH#2PhW-¿º©»[5Õ¹ÆBöç)Š®•ßÚNŸdÉ:â©ìÜ®›oDÍ'¤!õ²Æ™z£¦FPì))(£ÆO}§”6Wð¯ÑfJÊ‘8%ƒò¢L9ÂÐKø‚0tz*‘RùI?Sw8=\+gÒpX<—ð5eÜŽ–‡qŸŽ’İ;aTóÊ$÷•Z ãÝ5Ý¾í¥²+ní½ª™ðÆûºÎÇ®DÏÕÑÍuã•.Åkûý8.ÇýŽöæyz‘ñêå㤾*Ê:ÂY;J<ÙÓ<”þ¬‚ŽâŠ#V†v0Ç$¿+Ü=ƒµD éôLÿ©tBæ(ŠŠÛ«{PÕÛqNýý„GÀš;D–«ùÔ4|‡—^ y¥ðÄMx¬ÛÌ÷æ–+Œ‘ïBÑÁ³žìÓ©«†¬jÑ~5YÞiøæþÆÊ fš?¥bîÉü’âf|cŠnJ+?±šÑ¨•bW’nŠ7â!‚ªGØY¥ÑüÇ©ÕÙž@ÅuæÅÖ*ZŽfà·'“Ÿýäm]úJGgÊê—tî‚1_„NãœSi,üÒË,[("•8È/í¡.ßLf¹»d0¡d%ŒÁCð?2ÛÏÙ}2%Ÿ?d´y•ç\ºÃ#÷Ç+| y%le€"+áô£l¹áÓ¨b¹¬–¾Žù¬¾¨s«eÛ y›™J¹jú×\‹ ñ¾¨Òää0x°ß²:è1á¦>þŒ˜?àË)XуÀ¢dÀ̰8pú´ö${Ëöêå<´ãð…¦æ¿-mˆé…a•‹þ)²ÕÈÌ_þàî€íÚ³™ÃY1H[Lw‰Vi P½Š„ýŸ¥0ýƒ'}ÙÁ¹¾{ûZ”WÕ™/{¸†_,Ý<,¨A¯F§<3ˆÁÔYÖu¯Ù‚ï§þ€k+œ½ÿ^£ŠÈô«½Ý-ž{УƒR Uì‹Þ½¥¿2!ÒvµLÂÁ´C¹Ô, =ݧ/n2QŽþ¶Lhr@ïºã«ïY›2 €Kc;Û$|ÈE¬cûO‹«™,0‚þ *†H†÷  ‚ï‚ë0‚ç0‚ã *†H†÷   ‚v0‚r0 *†H†÷  0½wzt5éÛ‚PÊ…`}×§ò]R¬åªÝÀ`3ÿ]ü¹¿õh?©´ì‘K1¥£×Ã俟pbåÙ@µŠ¶”¹3D¸ÃÕë‚N"²PhÛl-®¢JXa TônÀ¯Í|#ˆÈd8Iµ³½}QHÏwko¢dŸCï¬n{ dU®Ô½¡wŽ2Z`ë‹NêÈR:ÌY=fˆCO÷³T6¤BwCVd…û˜w ˆ _£˜)Þšb ²ë¼D Üh_Y¨ÎÌ+$}!Ä3´:ÒÏeË0æ !« o²¡²ø0†@JÁø¤G>…òÎ7ý¨©ŽCÛŠà\rh>À#\ Ç©Hh~±;Ôód4›Ž„52ë7E²r}“-Ø‚®ÛJÈæëÿ€ž|âG®¿­OcÑåRÕ¹aáf…Å÷çL/E:¥6! ½˜©¹ô÷Þ˜ Ô™5A1Z0# *†H†÷  1vpp°—ÈsóúlN8.%ûvÿ¶03 *†H†÷  1&$client-certificate010!0 +æ ¯ `8tGŠËîíU¸±XýÁËy1îâqpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-certificate1.p120000644000175000017500000000311412770711161026163 0ustar danieldaniel0‚H0‚ *†H†÷  ‚ÿ‚û0‚÷0‚ç *†H†÷  ‚Ø0‚Ô0‚Í *†H†÷ 0 *†H†÷  02ÔrA_õæ)€‚ ûù9aŠ\Úb¼Åï ]/ò’ûÛ„*ú£6S…[½k¢GÞýó G…nGã~¼O®QZ^ÉÍKEÉßàiÿ3UK}lÜRH<.ý —wæ„õ•М^?*tôØ2±9JI5x³LL­ÁŠ?ôL6´n ˜Ç;çâ ó¨Ã¾–i‘9¸©¡ý÷EcgC›&ISOñ&úžG7_Æ#WRœ€æ1ýo¾â‚€‘ŒTéz¡§7øìªë?ÀäðP%êm¹¡Y.'y_f9ÈãÐP»áÌ[®I˜4©£*¨+ä%`ù$ölôÏ ó}‚–pœRùò«9Kø!T9(Š àÉ:Ãm™ˆ‘•À9¥¾u´ZjÑê±øéƒžû¿Â'¶^GÙÊ–D“º¸Ôl5û¢…Ñ÷s§•Ùd #¿wdm͘;RðKÔßÝiJ*êù a%ÐìÅ)g’w¤H¯¬—º;Ú©=l’¤;wÁÌ_Í£Ø!nƒµÌÒÚ‚ÇF#kð¸Ðwf“ı齌2¡ñÇ;s\Û‰‰ÁTԞוLA‰~ÁÐfš¶nÄKåáâÛû ÍP™¸Rh³¯T YÔY°uon]Í‹0ˆc”ŠlU®YGâ­D³ò¦¬2òôV­C—OH©ô:¢KéÏRœ¯O¤ŠkkX”Oª@ Hroˆ8€ÍD”6&sonn[¼ËÃÔ^?¿|{kŠg›'ZÔî€7NüìüºŽ“(öŸÔ³¥®U›]q0srÕ¦ý‡˜ÑßÖܳ^MÕL{‚\/î/i§ëx[AL(¯ª)_˜ÜXŠsxM«Óm7žú«©¼ïFÃz«u¯ =# + Yn0;0íèVļ{H~¤(‚ ÜΦ?íV*kÒÇ«$ÂêâP{ÍñuÌ®Émïé'k}î'úØéG‹Áje¨0|pÈ Ccýw¤’_ÙǪdæ¹^Š(*k7% ~mæãéù.:ýbB…vÑÿ•M ˆõašÐk 2«bÓ¤º§CC\ë<ñÁDËBŠ]d!ÃóÆåOpöoO1†u¤`aa¥-”ÓŨž!Oàãz¦©ÎáOÃk¸±rÛ¿îO)$ ¿°ÊõØp¬äç2JÜÌ<3Qük¥ÅÞ}üGÔËõŒ®˜OÓîÎäu½oæËuLð³i~1\0# *†H†÷  1ÉsA«¯å†iiÆj (FÙÖ05 *†H†÷  1(&client-certificate1010!0 +(F:è¿_ž|„¾¨AaïY_Y?nyeïâå qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-certificate1.pem0000644000175000017500000000213412770711161026343 0ustar danieldaniel-----BEGIN CERTIFICATE----- MIIDDDCCAsqgAwIBAgIEGzO0QTALBgcqhkjOOAQDBQAwMTEXMBUGA1UEAxMOVHJ1c3RlZC5DQS5j b20xFjAUBgNVBAoTDVRydXN0IE1lIEluYy4wIBcNMTYwMTEzMjIxOTE4WhgPMjI4OTEwMjcyMjE5 MThaMFwxDDAKBgNVBAsTA0RldjENMAsGA1UEBxMEQ2l0eTELMAkGA1UECBMCU1QxCzAJBgNVBAYT AlVTMRIwEAYDVQQDEwkxMjcuMC4wLjExDzANBgNVBAoTBkNsaWVudDCCAbcwggEsBgcqhkjOOAQB MIIBHwKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+AtlEmaUVdQCJR+1k9jVj6v8X1ujD2 y5tVbNeBO4AdNG/yZmC3a5lQpaSfn+gEexAiwk+7qdf+t8Yb+DtX58aophUPBPuD9tPFHsMCNVQT WhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdgUI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3e y7yrXDa4V7l5lK+7+jrqgvlXTAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+hMKBYTt88JMozIpuE8 FnqLVHyNKOCjrh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB TDv+z0kqA4GEAAKBgAsLC8PBAEzv2Vl4Ji1k3mVI49YzWsz6Yh/HPCjy1s9aueNRM0ZlhQWv3TIw gOcbIoUp10y4Rc4fsVIrjpoC4tmZCZmkimnoa+Lp0whDUlwWrEFZ971NqkQsmagfpuXVYeE4hB1Y OoETBpybd+liDaikymLWFqwd9XmuQlysEhWCo0IwQDAfBgNVHSMEGDAWgBSrEL6O+KB+mJHozd9v pemmAbEUljAdBgNVHQ4EFgQUBlPIzSsmgK6IwNtZitN/NrQEztMwCwYHKoZIzjgEAwUAAy8AMCwC FGxlMH0zwjoCJMfntSRAwxM+4JK7AhR6Y/CgFBrJCgDFAYkFH8ucHoii6w== -----END CERTIFICATE----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-private-key1.pem0000644000175000017500000000306112770711161026321 0ustar danieldanielBag Attributes friendlyName: client-certificate1 localKeyID: 54 69 6D 65 20 31 34 35 32 37 32 33 35 33 33 32 36 32 Key Attributes: -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBnjBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIY3SXzWdZ9g8CAggA MBQGCCqGSIb3DQMHBAgNjO/Glke9hgSCAVgtzKi1oXuMXuv2D7H2Mn4OQIevpn7S WMvJmFSNiNvIAmKhJjPyaPKYYgCMALYi+mvFWfv/EaQuiovX45GTMrCFM4MdUuo0 YCTEOB8ehrHEoyy76U61wN+EfdEYlS3/KfnbdnhHD342jdV+yO5T5pgpacu+5Inz IzvcBrGFehqTI9fq3Zkl1dOEpfrfahrO/8rq+UZQzqjIaiWi6irSFihQNsvVKUkd TLUDmSX591+dUblMlH8g/V3pY9EAEjdxGuY2mEqEe/B2WH74s3xyOb0UljkC6AmE MYGGXR8XK1RYrKQp3SwUMlisz72JhrfzvUlYEMRuclNKNNjyEPBO85iXLPFmSNQ5 4H/N/P3lO6WXny1Ea46kc5+ulC2CQkvetZhWcOtHvf4WRVt6wx2xQDhZwcUM7zDk uUV8pFqT1iUmx8k4Zasp1hNi0zSLnf3mKVPF3EFDTbU8qQ== -----END ENCRYPTED PRIVATE KEY----- Bag Attributes friendlyName: client-certificate localKeyID: 54 69 6D 65 20 31 33 36 33 37 39 34 34 32 33 34 36 33 Key Attributes: -----BEGIN ENCRYPTED PRIVATE KEY----- MIIBljBABgkqhkiG9w0BBQ0wMzAbBgkqhkiG9w0BBQwwDgQIFcxTKG24KKICAggA MBQGCCqGSIb3DQMHBAh/2ViSC9U9qQSCAVCM9V+dw+CnGKguFH5LYpCtoepRaDvC yTsGPmmJOh+wDObU8U+4kEYdGLCJgqblXWJEt9uAVOwg3EK30mSCT33N/VIbSbgv LadI7WjqtMKU5xJGscb71uGUdmiJrXLtp/1TnwNZM48QGpzuj+Eegn7j3BRX7bSS EwrUxqSm67ahi1/R2driAuZQxdvotBQNUq7ADZQVAISKMhblJs3Z7mX4EBxveS/f YIwDQ+ZfBfOnEhSNFxk6/zIxWqA0/3gFY2/M1uI3TvXuuOHags6+QuHHnpgrV7J+ 1Oaq5cAD1OlGd/fqerTxRdIUQMVixFVqMYZUEnqeiWOY/CxkynHh7MUT1/LaUN2d 7QVvpVXHvTvG4BPlApxIVV4/LoeYd4+jEkr/w7sq0msuMRP1qu1aNnl4XRtrvFOY hDpaYO/Lp7tv9r9geUszmWvlqkHm2nPocJo= -----END ENCRYPTED PRIVATE KEY----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client-request1.pem0000644000175000017500000000171212770711161025552 0ustar danieldaniel-----BEGIN NEW CERTIFICATE REQUEST----- MIICkDCCAk4CAQAwXDEMMAoGA1UECxMDRGV2MQ0wCwYDVQQHEwRDaXR5MQswCQYDVQQIEwJTVDEL MAkGA1UEBhMCVVMxEjAQBgNVBAMTCTEyNy4wLjAuMTEPMA0GA1UEChMGQ2xpZW50MIIBtzCCASwG ByqGSM44BAEwggEfAoGBAP1/U4EddRIpUt9KnC7s5Of2EbdSPO9EAMMeP4C2USZpRV1AIlH7WT2N WPq/xfW6MPbLm1Vs14E7gB00b/JmYLdrmVClpJ+f6AR7ECLCT7up1/63xhv4O1fnxqimFQ8E+4P2 08UewwI1VBNaFpEy9nXzrith1yrv8iIDGZ3RSAHHAhUAl2BQjxUjC8yykrmCouuEC/BYHPUCgYEA 9+GghdabPd7LvKtcNrhXuXmUr7v6OuqC+VdMCz0HgmdRWVeOutRZT+ZxBxCBgLRJFnEj6EwoFhO3 zwkyjMim4TwWeotUfI0o4KOuHiuzpnWRbqN/C/ohNWLx+2J6ASQ7zKTxvqhRkImog9/hWuWfBpKL Zl6Ae1UlZAFMO/7PSSoDgYQAAoGACwsLw8EATO/ZWXgmLWTeZUjj1jNazPpiH8c8KPLWz1q541Ez RmWFBa/dMjCA5xsihSnXTLhFzh+xUiuOmgLi2ZkJmaSKaehr4unTCENSXBasQVn3vU2qRCyZqB+m 5dVh4TiEHVg6gRMGnJt36WINqKTKYtYWrB31ea5CXKwSFYKgMDAuBgkqhkiG9w0BCQ4xITAfMB0G A1UdDgQWBBQGU8jNKyaArojA21mK0382tATO0zALBgcqhkjOOAQDBQADLwAwLAIUIH29x1jT3akD Y1rLTr6o5z5c++cCFAG+rzzJYzmBAhwTQsKtoQPtVCwA -----END NEW CERTIFICATE REQUEST----- qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/client.pkcs120000644000175000017500000000563712770711161024337 0ustar danieldaniel0‚ ›0‚ U *†H†÷  ‚ F‚ B0‚ >0‚ *†H†÷  ‚ô‚ð0‚ì0‚÷ *†H†÷   ‚Š0‚†0( *†H†÷  0 IüŽ …@hõã•k¿ÎbfX‚X“ºGÕ÷µ=pî§ávÏ }åéðàÕxÃÓ?œ ‘vÑ ­66òú³Ò€J—ðØ~þ¹iCï>_ÉüR 5¤½¨ZšH¬¢*›©¸î“Ï•h4Õ`ÿôuRÊŶ/y’¡á!ävƒ¶´_TbŸ(ÜÃTc$€ÅD`³…0ª¤~¿×­ÍáÛ«{ƒ¥‘B¯±áÕâ•%Ha…Färìý@‚/°>Š †–å ð®Î³{öìNjC7øí2ˆì­{jvG6!¶O‹G*öˆ™žÉ——6½ ã'ÐAÿT÷w['{S}6…­L?h·õ4êXݸŰ)Hj‡w(JE®×Âç²hªëý­ˆføhσˆòìc»˜±ú£zxæwåʽ9JYáµ.šÜLïà~¼«i‚oŒZÕô…ÇÙ—æ;Ó„½Šg¤†z6“ߎ¥1Z05 *†H†÷  1(&client-certificate10! *†H†÷  1Time 14527235332620‚í *†H†÷   ‚‚0‚~0( *†H†÷  0YMRš)H„u+¼çBw)%.È‚P¬¬˜utbæßIœýšáˆè¼°3¯Srao‰õ4Œ¹HA.ºÚJ²H…ìBdé.ñq‡š…bgžï²Ï¸RsË^7©ÿT³"[rýõT,â2ùš ‡ÄVBÚÄ^ÏÃrúÕÞí5IÉÏ2BgƵ{>ؼ‘u[7oÁŒÉtD§‡•Mâ EûFûáBÙꨟ³§4þ*¥…@ÞpYr]‹J¹ZͦeÃýÂçh!•†¿9Q´@‡È·Gg›ÔCÉé oôGÖ<Üû³ €—|ÒŽ®£ÓÀžY’A8¶Ì9Ü%t®÷Gß~Œ¼šð~6¸°ØbÐHp©°¼X;Œ'§+&U]t®/1ÿ@@ÖAËMçrî¤E<‹!=¬šA¤j¥ÌÇŽ—àD€øvw F­fý¢bÃ+̨ÿ½_V2°ï'ìyÛµhsxooSJá+HAEm+<³å”ã_’;ñÏ”O‡ãgâãÅ-¹Ùý`¸oÈd1hµ»W!Øâ@ñêFdý7òA‚®1ŽŸ]Ǻ+»ˆÞŸ²¤„_©ÿzdP3f¾ª¨<¥D䜦IûaÂL£9[I–Q±FÛ‹– ;4›iýaTŠxBUu¾êÓ0:s|g1|€¥6ÌU%Õ·T/v¡Æ^§e5ˆÑù3œ-ˆÏ­WèÔ«pt’>ö7†>Ðpëãðª÷í­ÇEa c“=ö¤ ùð¡¬d"@±™Æ®Bdlÿ›_꼟ÙðÄ=µ¿"VOuD:ŒúûDU2S[hÝÅFº{¿p§Å†þü–‰¦…Üg´KP7cF#qq÷©{°p±Y¯^óQÔ†B¸ÆWÌ•=›iŒ :Y@Dv'ðRDCBr*×¶÷•8_¡ÒW2,¡ë½¶Oz€\‘ qÑqhê¨"ˆØŒ•ÿ9$Št]ª¢SL&ì)™ O0pLÜ™夘d NǼ+ì&TgeÔ'c—Eóï×òÊ+âZ|Î)ÈÞ‹?Sû)]ãõ£I#]Á[c»¥Zð~r{"™FÉ´€õ°òÐC>Au+Œ Ó[e í%䃢WR.—XÔ;AfbÚåÝÇ"ÉÔúÊŽmzá7]}bÒ æó0)B³¢O~ì¹@'=$ ‚©ÇdºþÑrÎÕ»&áPÚ_Aïìü¼à댳«\Û‰5ˆž×䆉»0§ˆÄyæÜA2v·€vˆVwJXYŸãi=0»T>˜ÙYçÝÆJÈ3ËŽÚva‘¹X^)¯Õ*ê‰M…£u„Ù_a¡GV“Zí&ÔÓÄôe^è^Hé«0Hc;ð'·=SÐhZT_·õyÊ/¿ :gBۇе}Ÿ­®À¸l%uÔ*ØM›ï–«±þ‹\áÒ¤a¡;OuW[ˆaG¤²½ªÏŒÐâíÄ|šÇZ2舻ËvŒ­è†½Ëý®¿ú›aI†wÑ`±€°D9ÍfyõcSsÒŽv” ØÙ&ŽE1LÛ0¤pÈþ¹µƒ]ÊrHá©?HÈ“¦L>;ç¸×‡o7ªõ,m»Þ5-ýCá»ã¹´ð9»0=0!0 +|F`mqfÏ®4óSá+CªĪH¦| Ž‘lm¾Êh{œ$ôÐŒJŒqpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-certificate.p120000644000175000017500000000303212770711161026131 0ustar danieldaniel0‚0‚Ü *†H†÷  ‚Í‚É0‚Å0‚¿ *†H†÷  ‚°0‚¬0‚¥ *†H†÷ 0 *†H†÷  0œû(“ª.›€‚xÊ%g5)˳…ÏáþßyŸ¥Ì†„˜Þ5Éæâ2¤¦·'œ6$¢à‚<œŒˆ¬à¯6éãô€#š=[Ê(7æ,Õ“Cû%C~sý™ÍÞeŒ¶Ërboï¢ã‰"'|]°.•æ”2ñ¹®‹è"š1öû,ÍhNG ¿‘}lƒZ¢*b—ŠƒòïfôZKjj—q8‘þ[”¹MýQþ§Ø(CHVºO]¨rŠ0Ð$¬45Ñå6CËŽ^<:ïámsö޾‘þ~ZDx3ß|6Xõž$ðõdí ´ÖJt2“n@M0ª1ë.™HS͏ÄëãsÉßú4§Î'îKVXÌɬeØ–˜½£Á*—‰…9ª ¸]Zì Í< $= ¿Pá=΄±¨#¬#¥/” ÌÂOZiÎfLïþ1=ŸÖ½¤GPþC!?‹.t·Š—gIÀã?Á›š¼MÓËh+!TV]܉¦*eßË„´vŠ qG¤ Iýqi)1b» ø®©•ÝÈo¤™«ÒÄ]ÓܧJè\VŠVYGF|W6Y߀Y…#q]½?fØGçt.Ý$ji·%S]<3ès_Y³\eÁýq)_pÑ›´íKåÖk;_ÌnÎ(»„6OӃߒ˜æ[fÖ¹kP 'þX@èÅÆm|®—`ð[ÔZS;­R2g©(žßëjîå/Çn’°Ög4°jséÌ22Co>yL™4˜×ŽHKk ?âOÙ‡YJËUÉg­!òî;~ KyñØ‚H4^PSÑ q£Ñ”ótÆ^jÇÁtŽM}~ú½6á¼(±ríÆ#”9 ñQŸîÇLOI14úX».}©*N²;WD§ôI+·ñ~y޽ qž½ÏXœ¡c×PƺjÒã¿ ü­Êãô›D[ýTPŒšTåêœoõ{oÖGýÛjgCÄêØK§ó÷4Ó·ÛtåeØË×Áòi\®ë?þ=έ`¹RYî’.æOؘ@ ;þW{ ºù:Ô$¦ÅvZ,ÁjQ)Ìi&G¨^CSN{òApÍ@dœ¾£®^=NdW:Ðh‡®>ì M\í…~ŒÂø~…_V}XÖ…V HzAÇ´45¨+ ë´jÉ?rÒi#¼]õþ0‚þ *†H†÷  ‚ï‚ë0‚ç0‚ã *†H†÷   ‚v0‚r0 *†H†÷  0É ö[© ­œ‚Pý}‘¬œñ8ZÊp.YŒ”ÄmÚL1Ç¿÷àÌ©Ro(Æ€³Ñ‚ýþ½4Ë@øÄð/GÉ¡,{¢j$³~ÂÈe‰j&²T Hqt}gXˆ‘õÒ©í¤+¶xݬl! T:L1´šèˉ>†Ð‰Œ6²Ï ù¦i´>ËKÚDEiM@…9í'“Zv‰Ñ긦µ=Á)íÄ:%6ð Ýyº›²ÛtHm)Án±Xmi¯­Œfnƒ&ʧúy™-Ì ðQ‰<:„Í&h)EÈØ)Ôðž¥ïù5<<:'{˜™8râÙ@u’=ZçÇÂAó›>«‚Û¼zS ^WLÉqpÉkUvPç!ÛÅôÀx9Ú› ùv(e+£8™¹øÿ1 Ø)ôz¡I>ó¨»ç KòÃYoïÛ“–@õäiYyl2&¬!IÏ,Ê ~bÛh¡¡ã1šãr™¨lA1Z0# *†H†÷  1óÝ´ÜŠ¼óR‡t¶"§øs"µ03 *†H†÷  1&$server-certificate010!0 +*\Ü⦠<a¥B`ÊÁ ÍŸÈWÒ·(é·qpid-proton-0.14.0/tests/python/proton_tests/ssl_db/server-wc-certificate.p120000644000175000017500000000314012770711161026540 0ustar danieldaniel0‚\0‚" *†H†÷  ‚‚0‚ 0‚÷ *†H†÷  ‚è0‚ä0‚Ý *†H†÷ 0 *†H†÷  0rinoÜ!ù/€‚°wpËÚÄýúZ aB“áàè6Òu]û‹4H8…9’*ËÍgdîÉÛ\§äÅÖ™rV@jAk¦ÇÿƒÆ(-ÕÆ”+q}-K?*yõ?žäáˆÛ²ÈhR2.ƒFb£«ƒ_W#ËÉàÜJ¤Ó'R ž9é°tðQ;A"9CõMίb)?U¤oJá*³°TÌí:-óÇV²î..*% ‘SÄß|[?иÖ=ê§ü·=´öbmׯâøI"Ò5q0>4Ιq ýÍòœzá:…òùfÜÍ눠Ò4`!Á\ù©šU²èþl®èÊÚõpÜï{îä«°FG >í ª>ÿL+šEéyûÏN=©Ë´tƒÇµ5f®Qþ™–„²ó[0Ï`¬›N¥9ZLÚ>˜Ð"—hh:Æ«Ökã!§Õñ\Öä5fLcdz< ûEYîô<ÁI«Ï@$,>ܯ.þ\vŸóî6Ó-Jw…¬ºE6z…ÉÉÆè éwÓ·÷›¾j«•ƒŠ|ž!Ÿ+Ñ+H‰|a3áÞEÞØÄvùâeÑ'Ð{Y×\êÖiWb‰Éýl]öÆ8t´ã›Àl°Å‚Àõ¿øh´ hœŒ«‚*1ª=>C‚¢Ô›O¢Ç À¤Óû›~¤Ì7ó@¦â>Þ«ذØ5Î6¸ÅƒÔ‹S'95ÑvTîŸÛÊÎï²ÔvȯÜÓ¡3#‚4ìÿeWÓܺƒá2í'-ÓnUéDÑ'‡âáò«‚©RŒïÓ¦-%Í]ž_}ù·f?ù€`ÿ[ i8šIþþºûþ1†Râu†…Þw¦e™’hç¼/£!ÇZÝ@½'¦< £9êRƒq4ùô\lrš6yñÒ³É~q¼Sˆ¦÷ŒØ°¶~ä³9­þŠ•yÚÖ l8õ· Ma“â½3fqc_Èp;¾x¨±@Â=Š]û½"“híp$•‹g‰™¿R`îŸÇøÄBG"Ù,Öîåø,zÒ´ï^“Ád˜’ý6H2Ç0‚  *†H†÷  ‚ý‚ù0‚õ0‚ñ *†H†÷   ‚~0‚z0 *†H†÷  0GC2Êi@$‚Xq°©*ŽË'B¢ë1^áÈÀ£‘Ý£èD•ëü(`ÍÛ‚¿ë0h`Y“ÅóavÊû }ªë“Ù#æ"µ‡‹Ñ»Ãcâ8ËJÚ á úñ¼̸:³@kÄ9 *¹Ùå­±8„¸5|&Ï® Ž2¶£eÌ=®¢X¨$Ðâ¬8f±© ä'/vQ±î?œ°&EAB/KÔ7RLœ¨á¾¸ÒíÊ¢œJ§Ó‚ à³òF`ўȄÄü"ƒ°ç:zŒ\ÌD3ÿÏšÝBúo/ºPË»mZ¢ûÍêv›åŠ 䵿@õ—²ÌÎÓÍ€¾¼E®ªXßTΑÇdDj^ÿÚÅ{v  §äÝþT©R…¤,@Lýk_Γjß0Åë!rH#±l«F-ÅÊÅ#ðíO][¤ÉŽ˜½]Ba>Ô)êèqݱ®‰DœlfÄ1`0# *†H†÷  1XÞ|ëœs´›“ð=ê£'¸Þ Úž09 *†H†÷  1,*server-wc-certificate010!0 +…}ýe“dpÛí“›·ä /öÉA ;˜qpid-proton-0.14.0/tests/python/proton_tests/url.py0000644000175000017500000001402312770711161021727 0ustar danieldanielfrom __future__ import absolute_import # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 . import common from proton import Url class UrlTest(common.Test): def assertEqual(self, a, b): assert a == b, "%s != %s" % (a, b) def assertNotEqual(self, a, b): assert a != b, "%s == %s" % (a, b) def assertUrl(self, u, scheme, username, password, host, port, path): self.assertEqual((u.scheme, u.username, u.password, u.host, u.port, u.path), (scheme, username, password, host, port, path)) def testUrl(self): url = Url('amqp://me:secret@myhost:1234/foobar') self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar") self.assertUrl(url, 'amqp', 'me', 'secret', 'myhost', 1234, 'foobar') self.assertEqual(str(url), "amqp://me:secret@myhost:1234/foobar") def testDefaults(self): # Check that we allow None for scheme, port url = Url(username='me', password='secret', host='myhost', path='foobar', defaults=False) self.assertEqual(str(url), "me:secret@myhost/foobar") self.assertUrl(url, None, 'me', 'secret', 'myhost', None, 'foobar') self.assertEqual(str(Url("amqp://me:secret@myhost/foobar")), "amqp://me:secret@myhost:amqp/foobar") # Empty string vs. None for path self.assertEqual(Url("myhost/").path, "") assert Url("myhost", defaults=False).path is None # Expanding abbreviated url strings. for s, u in [ ("", "amqp://0.0.0.0:amqp"), ("foo", "amqp://foo:amqp"), (":1234", "amqp://0.0.0.0:1234"), ("/path", "amqp://0.0.0.0:amqp/path") ]: self.assertEqual(str(Url(s)), u) def assertPort(self, port, portint, portstr): self.assertEqual((port, port), (portint, portstr)) self.assertEqual((int(port), str(port)), (portint, portstr)) def testPort(self): self.assertPort(Url.Port('amqp'), 5672, 'amqp') self.assertPort(Url.Port(5672), 5672, '5672') self.assertPort(Url.Port(5671), 5671, '5671') self.assertEqual(Url.Port(5671)+1, 5672) # Treat as int self.assertEqual(str(Url.Port(5672)), '5672') self.assertPort(Url.Port(Url.Port('amqp')), 5672, 'amqp') self.assertPort(Url.Port(Url.Port(5672)), 5672, '5672') try: Url.Port('xxx') assert False, "Expected ValueError" except ValueError: pass self.assertEqual(str(Url("host:amqp", defaults=False)), "host:amqp") self.assertEqual(Url("host:amqp", defaults=False).port, 5672) def testArgs(self): u = Url("amqp://u:p@host:amqp/path", scheme='foo', host='bar', port=1234, path='garden', defaults=False) self.assertUrl(u, 'foo', 'u', 'p', 'bar', 1234, 'garden') u = Url(defaults=False) self.assertUrl(u, None, None, None, None, None, None) def assertRaises(self, exception, function, *args, **kwargs): try: function(*args, **kwargs) assert False, "Expected exception %s" % exception.__name__ except exception: pass def testMissing(self): self.assertUrl(Url(defaults=False), None, None, None, None, None, None) self.assertUrl(Url('amqp://', defaults=False), 'amqp', None, None, None, None, None) self.assertUrl(Url('username@', defaults=False), None, 'username', None, None, None, None) self.assertUrl(Url(':pass@', defaults=False), None, '', 'pass', None, None, None) self.assertUrl(Url('host', defaults=False), None, None, None, 'host', None, None) self.assertUrl(Url(':1234', defaults=False), None, None, None, None, 1234, None) self.assertUrl(Url('/path', defaults=False), None, None, None, None, None, 'path') for s in ['amqp://', 'username@', ':pass@', ':1234', '/path']: self.assertEqual(s, str(Url(s, defaults=False))) for s, full in [ ('amqp://', 'amqp://0.0.0.0:amqp'), ('username@', 'amqp://username@0.0.0.0:amqp'), (':pass@', 'amqp://:pass@0.0.0.0:amqp'), (':1234', 'amqp://0.0.0.0:1234'), ('/path', 'amqp://0.0.0.0:amqp/path'), ('foo/path', 'amqp://foo:amqp/path'), (':1234/path', 'amqp://0.0.0.0:1234/path') ]: self.assertEqual(str(Url(s)), full) def testAmqps(self): # Scheme defaults self.assertEqual(str(Url("me:secret@myhost/foobar")), "amqp://me:secret@myhost:amqp/foobar") # Correct port for amqps vs. amqps self.assertEqual(str(Url("amqps://me:secret@myhost/foobar")), "amqps://me:secret@myhost:amqps/foobar") self.assertPort(Url.Port('amqps'), 5671, 'amqps') self.assertEqual(str(Url("host:amqps", defaults=False)), "host:amqps") self.assertEqual(Url("host:amqps", defaults=False).port, 5671) def testEqual(self): self.assertEqual(Url("foo/path"), 'amqp://foo:amqp/path') self.assertEqual('amqp://foo:amqp/path', Url("foo/path")) self.assertEqual(Url("foo/path"), Url("foo/path")) self.assertNotEqual(Url("foo/path"), 'xamqp://foo:amqp/path') self.assertNotEqual('xamqp://foo:amqp/path', Url("foo/path")) self.assertNotEqual(Url("foo/path"), Url("bar/path")) qpid-proton-0.14.0/tests/python/proton_tests/__init__.py0000644000175000017500000000223112770711161022662 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import proton_tests.codec import proton_tests.engine import proton_tests.message import proton_tests.handler import proton_tests.reactor import proton_tests.reactor_interop import proton_tests.messenger import proton_tests.sasl import proton_tests.transport import proton_tests.ssl import proton_tests.interop import proton_tests.soak import proton_tests.url import proton_tests.utils qpid-proton-0.14.0/tests/python/proton_tests/codec.py0000644000175000017500000002737412770711161022217 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os, sys from . import common from proton import * from proton._compat import raise_, str2unicode, unichar, str2bin try: from uuid import uuid4 except ImportError: from proton import uuid4 class Test(common.Test): def setUp(self): self.data = Data() def tearDown(self): self.data = None class DataTest(Test): def testTopLevelNext(self): assert self.data.next() is None self.data.put_null() self.data.put_bool(False) self.data.put_int(0) assert self.data.next() is None self.data.rewind() assert self.data.next() == Data.NULL assert self.data.next() == Data.BOOL assert self.data.next() == Data.INT assert self.data.next() is None def testNestedNext(self): assert self.data.next() is None self.data.put_null() assert self.data.next() is None self.data.put_list() assert self.data.next() is None self.data.put_bool(False) assert self.data.next() is None self.data.rewind() assert self.data.next() is Data.NULL assert self.data.next() is Data.LIST self.data.enter() assert self.data.next() is None self.data.put_ubyte(0) assert self.data.next() is None self.data.put_uint(0) assert self.data.next() is None self.data.put_int(0) assert self.data.next() is None self.data.exit() assert self.data.next() is Data.BOOL assert self.data.next() is None self.data.rewind() assert self.data.next() is Data.NULL assert self.data.next() is Data.LIST assert self.data.enter() assert self.data.next() is Data.UBYTE assert self.data.next() is Data.UINT assert self.data.next() is Data.INT assert self.data.next() is None assert self.data.exit() assert self.data.next() is Data.BOOL assert self.data.next() is None def testEnterExit(self): assert self.data.next() is None assert not self.data.enter() self.data.put_list() assert self.data.enter() assert self.data.next() is None self.data.put_list() assert self.data.enter() self.data.put_list() assert self.data.enter() assert self.data.exit() assert self.data.get_list() == 0 assert self.data.exit() assert self.data.get_list() == 1 assert self.data.exit() assert self.data.get_list() == 1 assert not self.data.exit() assert self.data.get_list() == 1 assert self.data.next() is None self.data.rewind() assert self.data.next() is Data.LIST assert self.data.get_list() == 1 assert self.data.enter() assert self.data.next() is Data.LIST assert self.data.get_list() == 1 assert self.data.enter() assert self.data.next() is Data.LIST assert self.data.get_list() == 0 assert self.data.enter() assert self.data.next() is None assert self.data.exit() assert self.data.get_list() == 0 assert self.data.exit() assert self.data.get_list() == 1 assert self.data.exit() assert self.data.get_list() == 1 assert not self.data.exit() def put(self, putter, v): """More informative exception from putters, include bad value""" try: putter(v) except Exception: etype, value, trace = sys.exc_info() raise_(etype, etype("%s(%r): %s" % (putter.__name__, v, value)), trace) return putter # (bits, signed) for each integer type INT_TYPES = { "byte": (8, True), "ubyte": (8, False), "short": (16, True), "ushort": (16, False), "int": (32, True), "uint": (32, False), "long": (64, True), "ulong": (64, False) } def int_values(self, dtype): """Set of test values for integer type dtype, include extreme and medial values""" bits, signed = self.INT_TYPES[dtype] values = [0, 1, 2, 5, 42] if signed: min, max = -2**(bits-1), 2**(bits-1)-1 values.append(max // 2) values += [-i for i in values if i] values += [min, max] else: max = 2**(bits) - 1 values += [max // 2, max] return sorted(values) def _testArray(self, dtype, descriptor, atype, *values): if dtype: dTYPE = getattr(self.data, dtype.upper()) aTYPE = getattr(self.data, atype.upper()) self.data.put_array(dtype is not None, aTYPE) self.data.enter() if dtype is not None: putter = getattr(self.data, "put_%s" % dtype) self.put(putter, descriptor) putter = getattr(self.data, "put_%s" % atype) for v in values: self.put(putter, v) self.data.exit() self.data.rewind() assert self.data.next() == Data.ARRAY count, described, type = self.data.get_array() assert count == len(values), count if dtype is None: assert described == False else: assert described == True assert type == aTYPE, type assert self.data.enter() if described: assert self.data.next() == dTYPE getter = getattr(self.data, "get_%s" % dtype) gotten = getter() assert gotten == descriptor, gotten if values: getter = getattr(self.data, "get_%s" % atype) for v in values: assert self.data.next() == aTYPE gotten = getter() assert gotten == v, gotten assert self.data.next() is None assert self.data.exit() def testStringArray(self): self._testArray(None, None, "string", "one", "two", "three") def testDescribedStringArray(self): self._testArray("symbol", "url", "string", "one", "two", "three") def _test_int_array(self, atype): self._testArray(None, None, atype, *self.int_values(atype)) def testByteArray(self): self._test_int_array("byte") def testUbyteArray(self): self._test_int_array("ubyte") def testShortArray(self): self._test_int_array("short") def testUshortArray(self): self._test_int_array("ushort") def testIntArray(self): self._test_int_array("int") def testUintArray(self): self._test_int_array("uint") def testLongArray(self): self._test_int_array("long") def testUlongArray(self): self._test_int_array("ulong") def testUUIDArray(self): self._testArray(None, None, "uuid", uuid4(), uuid4(), uuid4()) def testEmptyArray(self): self._testArray(None, None, "null") def testDescribedEmptyArray(self): self._testArray("long", 0, "null") def _test(self, dtype, *values, **kwargs): eq=kwargs.get("eq", lambda x, y: x == y) ntype = getattr(Data, dtype.upper()) putter = getattr(self.data, "put_%s" % dtype) getter = getattr(self.data, "get_%s" % dtype) for v in values: self.put(putter, v) gotten = getter() assert eq(gotten, v), (gotten, v) self.data.rewind() for v in values: vtype = self.data.next() assert vtype == ntype, vtype gotten = getter() assert eq(gotten, v), (gotten, v) encoded = self.data.encode() copy = Data(0) while encoded: n = copy.decode(encoded) encoded = encoded[n:] copy.rewind() cgetter = getattr(copy, "get_%s" % dtype) for v in values: vtype = copy.next() assert vtype == ntype, vtype gotten = cgetter() assert eq(gotten, v), (gotten, v) def _test_int(self, itype): self._test(itype, *self.int_values(itype)) def testByte(self): self._test_int("byte") def testUbyte(self): self._test_int("ubyte") def testShort(self): self._test_int("short") def testUshort(self): self._test("ushort") def testInt(self): self._test_int("int") def testUint(self): self._test_int("uint") def testLong(self): self._test_int("long") def testUlong(self): self._test_int("ulong") def testString(self): self._test("string", "one", "two", "three", "this is a test", "") def testFloat(self): # we have to use a special comparison here because python # internaly only uses doubles and converting between floats and # doubles is imprecise self._test("float", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3, eq=lambda x, y: x - y < 0.000001) def testDouble(self): self._test("double", 0, 1, 2, 3, 0.1, 0.2, 0.3, -1, -2, -3, -0.1, -0.2, -0.3) def testBinary(self): self._test("binary", str2bin("this"), str2bin("is"), str2bin("a"), str2bin("test"), str2bin("of" "b\x00inary")) def testSymbol(self): self._test("symbol", symbol("this is a symbol test"), symbol("bleh"), symbol("blah")) def testTimestamp(self): self._test("timestamp", timestamp(0), timestamp(12345), timestamp(1000000)) def testChar(self): self._test("char", char('a'), char('b'), char('c'), char(unichar(0x20AC))) def testUUID(self): self._test("uuid", uuid4(), uuid4(), uuid4()) def testDecimal32(self): self._test("decimal32", decimal32(0), decimal32(1), decimal32(2), decimal32(3), decimal32(4), decimal32(2**30)) def testDecimal64(self): self._test("decimal64", decimal64(0), decimal64(1), decimal64(2), decimal64(3), decimal64(4), decimal64(2**60)) def testDecimal128(self): self._test("decimal128", decimal128(str2bin("fdsaasdf;lkjjkl;")), decimal128(str2bin("x"*16))) def testCopy(self): self.data.put_described() self.data.enter() self.data.put_ulong(123) self.data.put_map() self.data.enter() self.data.put_string("pi") self.data.put_double(3.14159265359) dst = Data() dst.copy(self.data) copy = dst.format() orig = self.data.format() assert copy == orig, (copy, orig) def testCopyNested(self): nested = [1, 2, 3, [4, 5, 6], 7, 8, 9] self.data.put_object(nested) dst = Data() dst.copy(self.data) assert dst.format() == self.data.format() def testCopyNestedArray(self): nested = [Array(UNDESCRIBED, Data.LIST, ["first", [Array(UNDESCRIBED, Data.INT, 1,2,3)]], ["second", [Array(UNDESCRIBED, Data.INT, 1,2,3)]], ["third", [Array(UNDESCRIBED, Data.INT, 1,2,3)]], ), "end"] self.data.put_object(nested) dst = Data() dst.copy(self.data) assert dst.format() == self.data.format() def testRoundTrip(self): obj = {symbol("key"): timestamp(1234), ulong(123): "blah", char("c"): "bleh", str2unicode("desc"): Described(symbol("url"), str2unicode("http://example.org")), str2unicode("array"): Array(UNDESCRIBED, Data.INT, 1, 2, 3), str2unicode("list"): [1, 2, 3, None, 4], str2unicode("boolean"): True} self.data.put_object(obj) enc = self.data.encode() data = Data() data.decode(enc) data.rewind() assert data.next() copy = data.get_object() assert copy == obj, (copy, obj) def testLookup(self): obj = {symbol("key"): str2unicode("value"), symbol("pi"): 3.14159, symbol("list"): [1, 2, 3, 4]} self.data.put_object(obj) self.data.rewind() self.data.next() self.data.enter() self.data.narrow() assert self.data.lookup("pi") assert self.data.get_object() == 3.14159 self.data.rewind() assert self.data.lookup("key") assert self.data.get_object() == str2unicode("value") self.data.rewind() assert self.data.lookup("list") assert self.data.get_object() == [1, 2, 3, 4] self.data.widen() self.data.rewind() assert not self.data.lookup("pi") qpid-proton-0.14.0/tests/python/proton_tests/common.py0000644000175000017500000004467212770711161022432 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 unittest import TestCase try: from unittest import SkipTest except: try: from unittest2 import SkipTest except: class SkipTest(Exception): pass from random import randint from threading import Thread from socket import socket, AF_INET, SOCK_STREAM from subprocess import Popen,PIPE,STDOUT import sys, os, string, subprocess from proton import Connection, Transport, SASL, Endpoint, Delivery, SSL from proton.reactor import Container from proton.handlers import CHandshaker, CFlowController from string import Template if sys.version_info[0] == 2 and sys.version_info[1] < 6: # this is for compatibility, apparently the version of jython we # use doesn't have the next() builtin. # we should remove this when we upgrade to a python 2.6+ compatible version # of jython #_DEF = object() This causes the test loader to fail (why?) class _dummy(): pass _DEF = _dummy def next(iter, default=_DEF): try: return iter.next() except StopIteration: if default is _DEF: raise else: return default # I may goto hell for this: import __builtin__ __builtin__.__dict__['next'] = next def free_tcp_ports(count=1): """ return a list of 'count' TCP ports that are free to used (ie. unbound) """ retry = 0 ports = [] sockets = [] while len(ports) != count: port = randint(49152, 65535) sockets.append( socket( AF_INET, SOCK_STREAM ) ) try: sockets[-1].bind( ("0.0.0.0", port ) ) ports.append( port ) retry = 0 except: retry += 1 assert retry != 100, "No free sockets available for test!" for s in sockets: s.close() return ports def free_tcp_port(): return free_tcp_ports(1)[0] def pump_uni(src, dst, buffer_size=1024): p = src.pending() c = dst.capacity() if c < 0: if p < 0: return False else: src.close_head() return True if p < 0: dst.close_tail() elif p == 0 or c == 0: return False else: binary = src.peek(min(c, buffer_size)) dst.push(binary) src.pop(len(binary)) return True def pump(transport1, transport2, buffer_size=1024): """ Transfer all pending bytes between two Proton engines by repeatedly calling peek/pop and push. Asserts that each engine accepts some bytes every time (unless it's already closed). """ while (pump_uni(transport1, transport2, buffer_size) or pump_uni(transport2, transport1, buffer_size)): pass def findfileinpath(filename, searchpath): """Find filename in the searchpath return absolute path to the file or None """ paths = searchpath.split(os.pathsep) for path in paths: if os.path.exists(os.path.join(path, filename)): return os.path.abspath(os.path.join(path, filename)) return None def isSSLPresent(): return SSL.present() createdSASLDb = False def _cyrusSetup(conf_dir): """Write out simple SASL config. """ saslpasswd = "" if 'SASLPASSWD' in os.environ: saslpasswd = os.environ['SASLPASSWD'] else: saslpasswd = findfileinpath('saslpasswd2', os.getenv('PATH')) or "" if os.path.exists(saslpasswd): t = Template("""sasldb_path: ${db} mech_list: EXTERNAL DIGEST-MD5 SCRAM-SHA-1 CRAM-MD5 PLAIN ANONYMOUS """) abs_conf_dir = os.path.abspath(conf_dir) subprocess.call(args=['rm','-rf',abs_conf_dir]) os.mkdir(abs_conf_dir) db = os.path.join(abs_conf_dir,'proton.sasldb') conf = os.path.join(abs_conf_dir,'proton-server.conf') f = open(conf, 'w') f.write(t.substitute(db=db)) f.close() cmd_template = Template("echo password | ${saslpasswd} -c -p -f ${db} -u proton user") cmd = cmd_template.substitute(db=db, saslpasswd=saslpasswd) subprocess.call(args=cmd, shell=True) os.environ['PN_SASL_CONFIG_PATH'] = abs_conf_dir global createdSASLDb createdSASLDb = True # Globally initialize Cyrus SASL configuration if SASL.extended(): _cyrusSetup('sasl_conf') def ensureCanTestExtendedSASL(): if not SASL.extended(): raise Skipped('Extended SASL not supported') if not createdSASLDb: raise Skipped("Can't Test Extended SASL: Couldn't create auth db") class DefaultConfig: defines = {} class Test(TestCase): config = DefaultConfig() def __init__(self, name): super(Test, self).__init__(name) self.name = name def configure(self, config): self.config = config def default(self, name, value, **profiles): default = value profile = self.config.defines.get("profile") if profile: default = profiles.get(profile, default) return self.config.defines.get(name, default) @property def delay(self): return float(self.default("delay", "1", fast="0.1")) @property def timeout(self): return float(self.default("timeout", "60", fast="10")) @property def verbose(self): return int(self.default("verbose", 0)) class Skipped(SkipTest): skipped = True class TestServer(object): """ Base class for creating test-specific message servers. """ def __init__(self, **kwargs): self.args = kwargs self.reactor = Container(self) self.host = "127.0.0.1" self.port = 0 if "host" in kwargs: self.host = kwargs["host"] if "port" in kwargs: self.port = kwargs["port"] self.handlers = [CFlowController(10), CHandshaker()] self.thread = Thread(name="server-thread", target=self.run) self.thread.daemon = True self.running = True self.conditions = [] def start(self): self.reactor.start() retry = 0 if self.port == 0: self.port = str(randint(49152, 65535)) retry = 10 while retry > 0: try: self.acceptor = self.reactor.acceptor(self.host, self.port) break except IOError: self.port = str(randint(49152, 65535)) retry -= 1 assert retry > 0, "No free port for server to listen on!" self.thread.start() def stop(self): self.running = False self.reactor.wakeup() self.thread.join() # Note: all following methods all run under the thread: def run(self): self.reactor.timeout = 3.14159265359 while self.reactor.process(): if not self.running: self.acceptor.close() self.reactor.stop() break def on_connection_bound(self, event): if "idle_timeout" in self.args: event.transport.idle_timeout = self.args["idle_timeout"] def on_connection_local_close(self, event): self.conditions.append(event.connection.condition) def on_delivery(self, event): event.delivery.settle() # # Classes that wrap the messenger applications msgr-send and msgr-recv. # These applications reside in the tests/tools/apps directory # class MessengerApp(object): """ Interface to control a MessengerApp """ def __init__(self): self._cmdline = None # options common to Receivers and Senders: self.ca_db = None self.certificate = None self.privatekey = None self.password = None self._output = None def start(self, verbose=False): """ Begin executing the test """ cmd = self.cmdline() self._verbose = verbose if self._verbose: print("COMMAND='%s'" % str(cmd)) #print("ENV='%s'" % str(os.environ.copy())) try: # Handle python launch by replacing script 'filename' with # 'python abspath-to-filename' in cmdline arg list. if cmd[0].endswith('.py'): foundfile = findfileinpath(cmd[0], os.getenv('PATH')) if foundfile is None: msg = "Unable to locate file '%s' in PATH" % cmd[0] raise Skipped("Skipping test - %s" % msg) del cmd[0:1] cmd.insert(0, foundfile) cmd.insert(0, sys.executable) self._process = Popen(cmd, stdout=PIPE, stderr=STDOUT, bufsize=4096, universal_newlines=True) except OSError: e = sys.exc_info()[1] print("ERROR: '%s'" % e) msg = "Unable to execute command '%s', is it in your PATH?" % cmd[0] # NOTE(flaper87): Skip the test if the command is not found. if e.errno == 2: raise Skipped("Skipping test - %s" % msg) assert False, msg self._ready() # wait for it to initialize def stop(self): """ Signal the client to start clean shutdown """ pass def wait(self): """ Wait for client to complete """ self._output = self._process.communicate() if self._verbose: print("OUTPUT='%s'" % self.stdout()) def status(self): """ Return status from client process """ return self._process.returncode def stdout(self): #self._process.communicate()[0] if not self._output or not self._output[0]: return "*** NO STDOUT ***" return self._output[0] def stderr(self): if not self._output or not self._output[1]: return "*** NO STDERR ***" return self._output[1] def cmdline(self): if not self._cmdline: self._build_command() return self._cmdline def _build_command(self): assert False, "_build_command() needs override" def _ready(self): assert False, "_ready() needs override" def _do_common_options(self): """ Common option handling """ if self.ca_db is not None: self._cmdline.append("-T") self._cmdline.append(str(self.ca_db)) if self.certificate is not None: self._cmdline.append("-C") self._cmdline.append(str(self.certificate)) if self.privatekey is not None: self._cmdline.append("-K") self._cmdline.append(str(self.privatekey)) if self.password is not None: self._cmdline.append("-P") self._cmdline.append("pass:" + str(self.password)) class MessengerSender(MessengerApp): """ Interface to configure a sending MessengerApp """ def __init__(self): MessengerApp.__init__(self) self._command = None # @todo make these properties self.targets = [] self.send_count = None self.msg_size = None self.send_batch = None self.outgoing_window = None self.report_interval = None self.get_reply = False self.timeout = None self.incoming_window = None self.recv_count = None self.name = None # command string? def _build_command(self): self._cmdline = self._command self._do_common_options() assert self.targets, "Missing targets, required for sender!" self._cmdline.append("-a") self._cmdline.append(",".join(self.targets)) if self.send_count is not None: self._cmdline.append("-c") self._cmdline.append(str(self.send_count)) if self.msg_size is not None: self._cmdline.append("-b") self._cmdline.append(str(self.msg_size)) if self.send_batch is not None: self._cmdline.append("-p") self._cmdline.append(str(self.send_batch)) if self.outgoing_window is not None: self._cmdline.append("-w") self._cmdline.append(str(self.outgoing_window)) if self.report_interval is not None: self._cmdline.append("-e") self._cmdline.append(str(self.report_interval)) if self.get_reply: self._cmdline.append("-R") if self.timeout is not None: self._cmdline.append("-t") self._cmdline.append(str(self.timeout)) if self.incoming_window is not None: self._cmdline.append("-W") self._cmdline.append(str(self.incoming_window)) if self.recv_count is not None: self._cmdline.append("-B") self._cmdline.append(str(self.recv_count)) if self.name is not None: self._cmdline.append("-N") self._cmdline.append(str(self.name)) def _ready(self): pass class MessengerReceiver(MessengerApp): """ Interface to configure a receiving MessengerApp """ def __init__(self): MessengerApp.__init__(self) self._command = None # @todo make these properties self.subscriptions = [] self.receive_count = None self.recv_count = None self.incoming_window = None self.timeout = None self.report_interval = None self.send_reply = False self.outgoing_window = None self.forwards = [] self.name = None # command string? def _build_command(self): self._cmdline = self._command self._do_common_options() self._cmdline += ["-X", "READY"] assert self.subscriptions, "Missing subscriptions, required for receiver!" self._cmdline.append("-a") self._cmdline.append(",".join(self.subscriptions)) if self.receive_count is not None: self._cmdline.append("-c") self._cmdline.append(str(self.receive_count)) if self.recv_count is not None: self._cmdline.append("-b") self._cmdline.append(str(self.recv_count)) if self.incoming_window is not None: self._cmdline.append("-w") self._cmdline.append(str(self.incoming_window)) if self.timeout is not None: self._cmdline.append("-t") self._cmdline.append(str(self.timeout)) if self.report_interval is not None: self._cmdline.append("-e") self._cmdline.append(str(self.report_interval)) if self.send_reply: self._cmdline.append("-R") if self.outgoing_window is not None: self._cmdline.append("-W") self._cmdline.append(str(self.outgoing_window)) if self.forwards: self._cmdline.append("-F") self._cmdline.append(",".join(self.forwards)) if self.name is not None: self._cmdline.append("-N") self._cmdline.append(str(self.name)) def _ready(self): """ wait for subscriptions to complete setup. """ r = self._process.stdout.readline() assert r.strip() == "READY", "Unexpected input while waiting for receiver to initialize: %s" % r class MessengerSenderC(MessengerSender): def __init__(self): MessengerSender.__init__(self) self._command = ["msgr-send"] class MessengerSenderValgrind(MessengerSenderC): """ Run the C sender under Valgrind """ def __init__(self, suppressions=None): if "VALGRIND" not in os.environ: raise Skipped("Skipping test - $VALGRIND not set.") MessengerSenderC.__init__(self) if not suppressions: suppressions = os.path.join(os.path.dirname(__file__), "valgrind.supp" ) self._command = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--trace-children=yes", "--leak-check=full", "--suppressions=%s" % suppressions] + self._command class MessengerReceiverC(MessengerReceiver): def __init__(self): MessengerReceiver.__init__(self) self._command = ["msgr-recv"] class MessengerReceiverValgrind(MessengerReceiverC): """ Run the C receiver under Valgrind """ def __init__(self, suppressions=None): if "VALGRIND" not in os.environ: raise Skipped("Skipping test - $VALGRIND not set.") MessengerReceiverC.__init__(self) if not suppressions: suppressions = os.path.join(os.path.dirname(__file__), "valgrind.supp" ) self._command = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--trace-children=yes", "--leak-check=full", "--suppressions=%s" % suppressions] + self._command class MessengerSenderPython(MessengerSender): def __init__(self): MessengerSender.__init__(self) self._command = ["msgr-send.py"] class MessengerReceiverPython(MessengerReceiver): def __init__(self): MessengerReceiver.__init__(self) self._command = ["msgr-recv.py"] class ReactorSenderC(MessengerSender): def __init__(self): MessengerSender.__init__(self) self._command = ["reactor-send"] class ReactorSenderValgrind(ReactorSenderC): """ Run the C sender under Valgrind """ def __init__(self, suppressions=None): if "VALGRIND" not in os.environ: raise Skipped("Skipping test - $VALGRIND not set.") ReactorSenderC.__init__(self) if not suppressions: suppressions = os.path.join(os.path.dirname(__file__), "valgrind.supp" ) self._command = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--trace-children=yes", "--leak-check=full", "--suppressions=%s" % suppressions] + self._command class ReactorReceiverC(MessengerReceiver): def __init__(self): MessengerReceiver.__init__(self) self._command = ["reactor-recv"] class ReactorReceiverValgrind(ReactorReceiverC): """ Run the C receiver under Valgrind """ def __init__(self, suppressions=None): if "VALGRIND" not in os.environ: raise Skipped("Skipping test - $VALGRIND not set.") ReactorReceiverC.__init__(self) if not suppressions: suppressions = os.path.join(os.path.dirname(__file__), "valgrind.supp" ) self._command = [os.environ["VALGRIND"], "--error-exitcode=42", "--quiet", "--trace-children=yes", "--leak-check=full", "--suppressions=%s" % suppressions] + self._command qpid-proton-0.14.0/tests/python/proton_tests/engine.py0000644000175000017500000023102512770711161022375 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import absolute_import import os, gc import sys from . import common from time import time, sleep from proton import * from .common import pump, Skipped from proton.reactor import Reactor from proton._compat import str2bin # older versions of gc do not provide the garbage list if not hasattr(gc, "garbage"): gc.garbage=[] # future test areas # + different permutations of setup # - creating deliveries and calling input/output before opening the session/link # + shrinking output_size down to something small? should the enginge buffer? # + resuming # - locally and remotely created deliveries with the same tag # Jython 2.5 needs this: try: bytes() except: bytes = str # and this... try: bytearray() except: def bytearray(x): return str2bin('\x00') * x OUTPUT_SIZE = 10*1024 class Test(common.Test): def __init__(self, *args): common.Test.__init__(self, *args) self._wires = [] def connection(self): c1 = Connection() c2 = Connection() t1 = Transport() t1.bind(c1) t2 = Transport() t2.bind(c2) self._wires.append((c1, t1, c2, t2)) mask1 = 0 mask2 = 0 for cat in ("TRACE_FRM", "TRACE_RAW"): trc = os.environ.get("PN_%s" % cat) if trc and trc.lower() in ("1", "2", "yes", "true"): mask1 = mask1 | getattr(Transport, cat) if trc == "2": mask2 = mask2 | getattr(Transport, cat) t1.trace(mask1) t2.trace(mask2) return c1, c2 def link(self, name, max_frame=None, idle_timeout=None): c1, c2 = self.connection() if max_frame: c1.transport.max_frame_size = max_frame[0] c2.transport.max_frame_size = max_frame[1] if idle_timeout: # idle_timeout in seconds expressed as float c1.transport.idle_timeout = idle_timeout[0] c2.transport.idle_timeout = idle_timeout[1] c1.open() c2.open() ssn1 = c1.session() ssn1.open() self.pump() ssn2 = c2.session_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE) ssn2.open() self.pump() snd = ssn1.sender(name) rcv = ssn2.receiver(name) return snd, rcv def cleanup(self): self._wires = [] def pump(self, buffer_size=OUTPUT_SIZE): for c1, t1, c2, t2 in self._wires: pump(t1, t2, buffer_size) class ConnectionTest(Test): def setUp(self): gc.enable() self.c1, self.c2 = self.connection() def cleanup(self): # release resources created by this class super(ConnectionTest, self).cleanup() self.c1 = None self.c2 = None def tearDown(self): self.cleanup() gc.collect() assert not gc.garbage def test_open_close(self): assert self.c1.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT self.c1.open() self.pump() assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE self.c2.open() self.pump() assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.c1.close() self.pump() assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED self.c2.close() self.pump() assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert self.c2.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED def test_simultaneous_open_close(self): assert self.c1.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT assert self.c2.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT self.c1.open() self.c2.open() self.pump() assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.c1.close() self.c2.close() self.pump() assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert self.c2.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED def test_capabilities(self): self.c1.offered_capabilities = Array(UNDESCRIBED, Data.SYMBOL, symbol("O_one"), symbol("O_two"), symbol("O_three")) self.c1.desired_capabilities = Array(UNDESCRIBED, Data.SYMBOL, symbol("D_one"), symbol("D_two"), symbol("D_three")) self.c1.open() assert self.c2.remote_offered_capabilities is None assert self.c2.remote_desired_capabilities is None self.pump() assert self.c2.remote_offered_capabilities == self.c1.offered_capabilities, \ (self.c2.remote_offered_capabilities, self.c1.offered_capabilities) assert self.c2.remote_desired_capabilities == self.c1.desired_capabilities, \ (self.c2.remote_desired_capabilities, self.c1.desired_capabilities) def test_condition(self): self.c1.open() self.c2.open() self.pump() assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"}) self.c1.condition = cond self.c1.close() self.pump() assert self.c1.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED rcond = self.c2.remote_condition assert rcond == cond, (rcond, cond) def test_properties(self, p1={symbol("key"): symbol("value")}, p2=None): self.c1.properties = p1 self.c2.properties = p2 self.c1.open() self.c2.open() self.pump() assert self.c2.remote_properties == p1, (self.c2.remote_properties, p1) assert self.c1.remote_properties == p2, (self.c2.remote_properties, p2) # The proton implementation limits channel_max to 32767. # If I set the application's limit lower than that, I should # get my wish. If I set it higher -- not. def test_channel_max_low(self, value=1234): self.c1.transport.channel_max = value self.c1.open() self.pump() assert self.c1.transport.channel_max == value, (self.c1.transport.channel_max, value) def test_channel_max_high(self, value=65535): self.c1.transport.channel_max = value self.c1.open() self.pump() if "java" in sys.platform: assert self.c1.transport.channel_max == 65535, (self.c1.transport.channel_max, value) else: assert self.c1.transport.channel_max == 32767, (self.c1.transport.channel_max, value) def test_channel_max_raise_and_lower(self): if "java" in sys.platform: upper_limit = 65535 else: upper_limit = 32767 # It's OK to lower the max below upper_limit. self.c1.transport.channel_max = 12345 assert self.c1.transport.channel_max == 12345 # But it won't let us raise the limit above PN_IMPL_CHANNEL_MAX. self.c1.transport.channel_max = 65535 assert self.c1.transport.channel_max == upper_limit # send the OPEN frame self.c1.open() self.pump() # Now it's too late to make any change, because # we have already sent the OPEN frame. try: self.c1.transport.channel_max = 666 assert False, "expected session exception" except: pass assert self.c1.transport.channel_max == upper_limit def test_channel_max_limits_sessions(self): return # This is an index -- so max number of channels should be 1. self.c1.transport.channel_max = 0 self.c1.open() self.c2.open() ssn_0 = self.c2.session() assert ssn_0 != None ssn_0.open() self.pump() try: ssn_1 = self.c2.session() assert False, "expected session exception" except SessionException: pass def test_cleanup(self): self.c1.open() self.c2.open() self.pump() assert self.c1.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE t1 = self.c1.transport t2 = self.c2.transport c2 = self.c2 self.c1.close() # release all references to C1, except that held by the transport self.cleanup() gc.collect() # transport should flush last state from C1: pump(t1, t2) assert c2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED def test_user_config(self): if "java" in sys.platform: raise Skipped("Unsupported API") self.c1.user = "vindaloo" self.c1.password = "secret" self.c1.open() self.pump() self.c2.user = "leela" self.c2.password = "trustno1" self.c2.open() self.pump() assert self.c1.user == "vindaloo", self.c1.user assert self.c1.password == None, self.c1.password assert self.c2.user == "leela", self.c2.user assert self.c2.password == None, self.c2.password class SessionTest(Test): def setUp(self): gc.enable() self.c1, self.c2 = self.connection() self.ssn = self.c1.session() self.c1.open() self.c2.open() def cleanup(self): # release resources created by this class super(SessionTest, self).cleanup() self.c1 = None self.c2 = None self.ssn = None def tearDown(self): self.cleanup() gc.collect() assert not gc.garbage def test_open_close(self): assert self.ssn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT self.ssn.open() assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT self.pump() assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT) assert ssn != None assert ssn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT ssn.open() assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT self.pump() assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE ssn.close() assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.pump() assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED self.ssn.close() assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED self.pump() assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED def test_simultaneous_close(self): self.ssn.open() self.pump() ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT) assert ssn != None ssn.open() self.pump() assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.ssn.close() ssn.close() assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE self.pump() assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED def test_closing_connection(self): self.ssn.open() self.pump() self.c1.close() self.pump() self.ssn.close() self.pump() def test_condition(self): self.ssn.open() self.pump() ssn = self.c2.session_head(Endpoint.REMOTE_ACTIVE | Endpoint.LOCAL_UNINIT) assert ssn != None ssn.open() self.pump() assert self.ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"}) self.ssn.condition = cond self.ssn.close() self.pump() assert self.ssn.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED rcond = ssn.remote_condition assert rcond == cond, (rcond, cond) def test_cleanup(self): snd, rcv = self.link("test-link") snd.open() rcv.open() self.pump() snd_ssn = snd.session rcv_ssn = rcv.session assert rcv_ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.ssn = None snd_ssn.close() snd_ssn.free() del snd_ssn gc.collect() self.pump() assert rcv_ssn.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED def test_reopen_on_same_session_without_free(self): """ confirm that a link is correctly opened when attaching to a previously closed link *that has not been freed yet* on the same session """ self.ssn.open() self.pump() ssn2 = self.c2.session_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE) ssn2.open() self.pump() snd = self.ssn.sender("test-link") rcv = ssn2.receiver("test-link") assert snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT assert rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT snd.open() rcv.open() self.pump() assert snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE snd.close() rcv.close() self.pump() assert snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED snd = self.ssn.sender("test-link") rcv = ssn2.receiver("test-link") assert snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT assert rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT snd.open() rcv.open() self.pump() assert snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE def test_set_get_outgoing_window(self): assert self.ssn.outgoing_window == 2147483647 self.ssn.outgoing_window = 1024 assert self.ssn.outgoing_window == 1024 class LinkTest(Test): def setUp(self): gc.enable() self.snd, self.rcv = self.link("test-link") def cleanup(self): # release resources created by this class super(LinkTest, self).cleanup() self.snd = None self.rcv = None def tearDown(self): self.cleanup() gc.collect() assert not gc.garbage, gc.garbage def test_open_close(self): assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT self.snd.open() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT self.pump() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE self.rcv.open() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.pump() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.snd.close() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.pump() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED self.rcv.close() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED self.pump() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED def test_simultaneous_open_close(self): assert self.snd.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT assert self.rcv.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_UNINIT self.snd.open() self.rcv.open() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_UNINIT self.pump() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.snd.close() self.rcv.close() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE self.pump() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED assert self.rcv.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_CLOSED def test_multiple(self): rcv = self.snd.session.receiver("second-rcv") assert rcv.name == "second-rcv" self.snd.open() rcv.open() self.pump() c2 = self.rcv.session.connection l = c2.link_head(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE) while l: l.open() l = l.next(Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE) self.pump() assert self.snd assert rcv self.snd.close() rcv.close() ssn = rcv.session conn = ssn.connection ssn.close() conn.close() self.pump() def test_closing_session(self): self.snd.open() self.rcv.open() ssn1 = self.snd.session self.pump() ssn1.close() self.pump() self.snd.close() self.pump() def test_closing_connection(self): self.snd.open() self.rcv.open() ssn1 = self.snd.session c1 = ssn1.connection self.pump() c1.close() self.pump() self.snd.close() self.pump() def assertEqualTermini(self, t1, t2): assert t1.type == t2.type, (t1.type, t2.type) assert t1.address == t2.address, (t1.address, t2.address) assert t1.durability == t2.durability, (t1.durability, t2.durability) assert t1.expiry_policy == t2.expiry_policy, (t1.expiry_policy, t2.expiry_policy) assert t1.timeout == t2.timeout, (t1.timeout, t2.timeout) assert t1.dynamic == t2.dynamic, (t1.dynamic, t2.dynamic) for attr in ["properties", "capabilities", "outcomes", "filter"]: d1 = getattr(t1, attr) d2 = getattr(t2, attr) assert d1.format() == d2.format(), (attr, d1.format(), d2.format()) def _test_source_target(self, config_source, config_target): if config_source is None: self.snd.source.type = Terminus.UNSPECIFIED else: config_source(self.snd.source) if config_target is None: self.snd.target.type = Terminus.UNSPECIFIED else: config_target(self.snd.target) self.snd.open() self.pump() self.assertEqualTermini(self.rcv.remote_source, self.snd.source) self.assertEqualTermini(self.rcv.remote_target, self.snd.target) self.rcv.target.copy(self.rcv.remote_target) self.rcv.source.copy(self.rcv.remote_source) self.rcv.open() self.pump() self.assertEqualTermini(self.snd.remote_target, self.snd.target) self.assertEqualTermini(self.snd.remote_source, self.snd.source) def test_source_target(self): self._test_source_target(TerminusConfig(address="source"), TerminusConfig(address="target")) def test_source(self): self._test_source_target(TerminusConfig(address="source"), None) def test_target(self): self._test_source_target(None, TerminusConfig(address="target")) def test_coordinator(self): self._test_source_target(None, TerminusConfig(type=Terminus.COORDINATOR)) def test_source_target_full(self): self._test_source_target(TerminusConfig(address="source", timeout=3, dist_mode=Terminus.DIST_MODE_MOVE, filter=[("int", 1), ("symbol", "two"), ("string", "three")], capabilities=["one", "two", "three"]), TerminusConfig(address="source", timeout=7, capabilities=[])) def test_distribution_mode(self): self._test_source_target(TerminusConfig(address="source", dist_mode=Terminus.DIST_MODE_COPY), TerminusConfig(address="target")) assert self.rcv.remote_source.distribution_mode == Terminus.DIST_MODE_COPY assert self.rcv.remote_target.distribution_mode == Terminus.DIST_MODE_UNSPECIFIED def test_dynamic_link(self): self._test_source_target(TerminusConfig(address=None, dynamic=True), None) assert self.rcv.remote_source.dynamic assert self.rcv.remote_source.address is None def test_condition(self): self.snd.open() self.rcv.open() self.pump() assert self.snd.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE cond = Condition("blah:bleh", "this is a description", {symbol("foo"): "bar"}) self.snd.condition = cond self.snd.close() self.pump() assert self.snd.state == Endpoint.LOCAL_CLOSED | Endpoint.REMOTE_ACTIVE assert self.rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED rcond = self.rcv.remote_condition assert rcond == cond, (rcond, cond) def test_settle_mode(self): self.snd.snd_settle_mode = Link.SND_UNSETTLED assert self.snd.snd_settle_mode == Link.SND_UNSETTLED self.rcv.rcv_settle_mode = Link.RCV_SECOND assert self.rcv.rcv_settle_mode == Link.RCV_SECOND assert self.snd.remote_rcv_settle_mode != Link.RCV_SECOND assert self.rcv.remote_snd_settle_mode != Link.SND_UNSETTLED self.snd.open() self.rcv.open() self.pump() assert self.snd.remote_rcv_settle_mode == Link.RCV_SECOND assert self.rcv.remote_snd_settle_mode == Link.SND_UNSETTLED def test_cleanup(self): snd, rcv = self.link("test-link") snd.open() rcv.open() self.pump() assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE snd.close() snd.free() del snd gc.collect() self.pump() assert rcv.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED class TerminusConfig: def __init__(self, type=None, address=None, timeout=None, durability=None, filter=None, capabilities=None, dynamic=False, dist_mode=None): self.address = address self.timeout = timeout self.durability = durability self.filter = filter self.capabilities = capabilities self.dynamic = dynamic self.dist_mode = dist_mode self.type = type def __call__(self, terminus): if self.type is not None: terminus.type = self.type if self.address is not None: terminus.address = self.address if self.timeout is not None: terminus.timeout = self.timeout if self.durability is not None: terminus.durability = self.durability if self.capabilities is not None: terminus.capabilities.put_array(False, Data.SYMBOL) terminus.capabilities.enter() for c in self.capabilities: terminus.capabilities.put_symbol(c) if self.filter is not None: terminus.filter.put_map() terminus.filter.enter() for (t, v) in self.filter: setter = getattr(terminus.filter, "put_%s" % t) setter(v) if self.dynamic: terminus.dynamic = True if self.dist_mode is not None: terminus.distribution_mode = self.dist_mode class TransferTest(Test): def setUp(self): gc.enable() self.snd, self.rcv = self.link("test-link") self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() def cleanup(self): # release resources created by this class super(TransferTest, self).cleanup() self.c1 = None self.c2 = None self.snd = None self.rcv = None def tearDown(self): self.cleanup() gc.collect() assert not gc.garbage def test_work_queue(self): assert self.c1.work_head is None self.snd.delivery("tag") assert self.c1.work_head is None self.rcv.flow(1) self.pump() d = self.c1.work_head assert d is not None tag = d.tag assert tag == "tag", tag assert d.writable n = self.snd.send(str2bin("this is a test")) assert self.snd.advance() assert self.c1.work_head is None self.pump() d = self.c2.work_head assert d.tag == "tag" assert d.readable def test_multiframe(self): self.rcv.flow(1) self.snd.delivery("tag") msg = str2bin("this is a test") n = self.snd.send(msg) assert n == len(msg) self.pump() d = self.rcv.current assert d assert d.tag == "tag", repr(d.tag) assert d.readable binary = self.rcv.recv(1024) assert binary == msg, (binary, msg) binary = self.rcv.recv(1024) assert binary == str2bin("") msg = str2bin("this is more") n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump() binary = self.rcv.recv(1024) assert binary == msg, (binary, msg) binary = self.rcv.recv(1024) assert binary is None def test_disposition(self): self.rcv.flow(1) self.pump() sd = self.snd.delivery("tag") msg = str2bin("this is a test") n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump() rd = self.rcv.current assert rd is not None assert rd.tag == sd.tag rmsg = self.rcv.recv(1024) assert rmsg == msg rd.update(Delivery.ACCEPTED) self.pump() rdisp = sd.remote_state ldisp = rd.local_state assert rdisp == ldisp == Delivery.ACCEPTED, (rdisp, ldisp) assert sd.updated sd.update(Delivery.ACCEPTED) self.pump() assert sd.local_state == rd.remote_state == Delivery.ACCEPTED sd.settle() def test_delivery_id_ordering(self): self.rcv.flow(1024) self.pump(buffer_size=64*1024) #fill up delivery buffer on sender for m in range(1024): sd = self.snd.delivery("tag%s" % m) msg = ("message %s" % m).encode('ascii') n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump(buffer_size=64*1024) #receive a session-windows worth of messages and accept them for m in range(1024): rd = self.rcv.current assert rd is not None, m assert rd.tag == ("tag%s" % m), (rd.tag, m) msg = self.rcv.recv(1024) assert msg == ("message %s" % m).encode('ascii'), (msg, m) rd.update(Delivery.ACCEPTED) rd.settle() self.pump(buffer_size=64*1024) #add some new deliveries for m in range(1024, 1450): sd = self.snd.delivery("tag%s" % m) msg = ("message %s" % m).encode('ascii') n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() #handle all disposition changes to sent messages d = self.c1.work_head while d: next_d = d.work_next if d.updated: d.update(Delivery.ACCEPTED) d.settle() d = next_d #submit some more deliveries for m in range(1450, 1500): sd = self.snd.delivery("tag%s" % m) msg = ("message %s" % m).encode('ascii') n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump(buffer_size=64*1024) self.rcv.flow(1024) self.pump(buffer_size=64*1024) #verify remaining messages can be received and accepted for m in range(1024, 1500): rd = self.rcv.current assert rd is not None, m assert rd.tag == ("tag%s" % m), (rd.tag, m) msg = self.rcv.recv(1024) assert msg == ("message %s" % m).encode('ascii'), (msg, m) rd.update(Delivery.ACCEPTED) rd.settle() def test_cleanup(self): self.rcv.flow(10) self.pump() for x in range(10): self.snd.delivery("tag%d" % x) msg = str2bin("this is a test") n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.snd.close() self.snd.free() self.snd = None gc.collect() self.pump() for x in range(10): rd = self.rcv.current assert rd is not None assert rd.tag == "tag%d" % x rmsg = self.rcv.recv(1024) assert self.rcv.advance() assert rmsg == msg # close of snd should've settled: assert rd.settled rd.settle() class MaxFrameTransferTest(Test): def setUp(self): pass def cleanup(self): # release resources created by this class super(MaxFrameTransferTest, self).cleanup() self.c1 = None self.c2 = None self.snd = None self.rcv = None def tearDown(self): self.cleanup() def message(self, size): parts = [] for i in range(size): parts.append(str(i)) return "/".join(parts)[:size].encode("utf-8") def testMinFrame(self): """ Configure receiver to support minimum max-frame as defined by AMQP-1.0. Verify transfer of messages larger than 512. """ self.snd, self.rcv = self.link("test-link", max_frame=[0,512]) self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() assert self.rcv.session.connection.transport.max_frame_size == 512 assert self.snd.session.connection.transport.remote_max_frame_size == 512 self.rcv.flow(1) self.snd.delivery("tag") msg = self.message(513) n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump() binary = self.rcv.recv(513) assert binary == msg binary = self.rcv.recv(1024) assert binary == None def testOddFrame(self): """ Test an odd sized max limit with data that will require multiple frames to be transfered. """ self.snd, self.rcv = self.link("test-link", max_frame=[0,521]) self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() assert self.rcv.session.connection.transport.max_frame_size == 521 assert self.snd.session.connection.transport.remote_max_frame_size == 521 self.rcv.flow(2) self.snd.delivery("tag") msg = ("X" * 1699).encode('utf-8') n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump() binary = self.rcv.recv(1699) assert binary == msg binary = self.rcv.recv(1024) assert binary == None self.rcv.advance() self.snd.delivery("gat") msg = self.message(1426) n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump() binary = self.rcv.recv(1426) assert binary == msg self.pump() binary = self.rcv.recv(1024) assert binary == None def testSendQueuedMultiFrameMessages(self, sendSingleFrameMsg = False): """ Test that multiple queued messages on the same link with multi-frame content are sent correctly. Use an odd max frame size, send enough data to use many. """ self.snd, self.rcv = self.link("test-link", max_frame=[0,517]) self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() assert self.rcv.session.connection.transport.max_frame_size == 517 assert self.snd.session.connection.transport.remote_max_frame_size == 517 self.rcv.flow(5) self.pump() # Send a delivery with 5 frames, all bytes as X1234 self.snd.delivery("tag") msg = ("X1234" * 425).encode('utf-8') assert 2125 == len(msg) n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() # Send a delivery with 5 frames, all bytes as Y5678 self.snd.delivery("tag2") msg2 = ("Y5678" * 425).encode('utf-8') assert 2125 == len(msg2) n = self.snd.send(msg2) assert n == len(msg2) assert self.snd.advance() self.pump() if sendSingleFrameMsg: # Send a delivery with 1 frame self.snd.delivery("tag3") msg3 = ("Z").encode('utf-8') assert 1 == len(msg3) n = self.snd.send(msg3) assert n == len(msg3) assert self.snd.advance() self.pump() binary = self.rcv.recv(5000) self.assertEqual(binary, msg) self.rcv.advance() binary2 = self.rcv.recv(5000) self.assertEqual(binary2, msg2) self.rcv.advance() if sendSingleFrameMsg: binary3 = self.rcv.recv(5000) self.assertEqual(binary3, msg3) self.rcv.advance() self.pump() def testSendQueuedMultiFrameMessagesThenSingleFrameMessage(self): self.testSendQueuedMultiFrameMessages(sendSingleFrameMsg = True) def testBigMessage(self): """ Test transfering a big message. """ self.snd, self.rcv = self.link("test-link") self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() self.rcv.flow(2) self.snd.delivery("tag") msg = self.message(1024*256) n = self.snd.send(msg) assert n == len(msg) assert self.snd.advance() self.pump() binary = self.rcv.recv(1024*256) assert binary == msg binary = self.rcv.recv(1024) assert binary == None class IdleTimeoutTest(Test): def setUp(self): pass def cleanup(self): # release resources created by this class super(IdleTimeoutTest, self).cleanup() self.snd = None self.rcv = None self.c1 = None self.c2 = None def tearDown(self): self.cleanup() def message(self, size): parts = [] for i in range(size): parts.append(str(i)) return "/".join(parts)[:size] def testGetSet(self): """ Verify the configuration and negotiation of the idle timeout. """ self.snd, self.rcv = self.link("test-link", idle_timeout=[1.0,2.0]) self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() # proton advertises 1/2 the configured timeout to the peer: assert self.rcv.session.connection.transport.idle_timeout == 2.0 assert self.rcv.session.connection.transport.remote_idle_timeout == 0.5 assert self.snd.session.connection.transport.idle_timeout == 1.0 assert self.snd.session.connection.transport.remote_idle_timeout == 1.0 def testTimeout(self): """ Verify the AMQP Connection idle timeout. """ # snd will timeout the Connection if no frame is received within 1000 ticks self.snd, self.rcv = self.link("test-link", idle_timeout=[1.0,0]) self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() t_snd = self.snd.session.connection.transport t_rcv = self.rcv.session.connection.transport assert t_rcv.idle_timeout == 0.0 # proton advertises 1/2 the timeout (see spec) assert t_rcv.remote_idle_timeout == 0.5 assert t_snd.idle_timeout == 1.0 assert t_snd.remote_idle_timeout == 0.0 sndr_frames_in = t_snd.frames_input rcvr_frames_out = t_rcv.frames_output # at t+1msec, nothing should happen: clock = 0.001 assert t_snd.tick(clock) == 1.001, "deadline for remote timeout" assert t_rcv.tick(clock) == 0.251, "deadline to send keepalive" self.pump() assert sndr_frames_in == t_snd.frames_input, "unexpected received frame" # at one tick from expected idle frame send, nothing should happen: clock = 0.250 assert t_snd.tick(clock) == 1.001, "deadline for remote timeout" assert t_rcv.tick(clock) == 0.251, "deadline to send keepalive" self.pump() assert sndr_frames_in == t_snd.frames_input, "unexpected received frame" # this should cause rcvr to expire and send a keepalive clock = 0.251 assert t_snd.tick(clock) == 1.001, "deadline for remote timeout" assert t_rcv.tick(clock) == 0.501, "deadline to send keepalive" self.pump() sndr_frames_in += 1 rcvr_frames_out += 1 assert sndr_frames_in == t_snd.frames_input, "unexpected received frame" assert rcvr_frames_out == t_rcv.frames_output, "unexpected frame" # since a keepalive was received, sndr will rebase its clock against this tick: # and the receiver should not change its deadline clock = 0.498 assert t_snd.tick(clock) == 1.498, "deadline for remote timeout" assert t_rcv.tick(clock) == 0.501, "deadline to send keepalive" self.pump() assert sndr_frames_in == t_snd.frames_input, "unexpected received frame" # now expire sndr clock = 1.499 t_snd.tick(clock) self.pump() assert self.c2.state & Endpoint.REMOTE_CLOSED assert self.c2.remote_condition.name == "amqp:resource-limit-exceeded" class CreditTest(Test): def setUp(self): self.snd, self.rcv = self.link("test-link", max_frame=(16*1024, 16*1024)) self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() def cleanup(self): # release resources created by this class super(CreditTest, self).cleanup() self.c1 = None self.snd = None self.c2 = None self.rcv2 = None self.snd2 = None def tearDown(self): self.cleanup() def testCreditSender(self, count=1024): credit = self.snd.credit assert credit == 0, credit self.rcv.flow(10) self.pump() credit = self.snd.credit assert credit == 10, credit self.rcv.flow(count) self.pump() credit = self.snd.credit assert credit == 10 + count, credit def testCreditReceiver(self): self.rcv.flow(10) self.pump() assert self.rcv.credit == 10, self.rcv.credit d = self.snd.delivery("tag") assert d assert self.snd.advance() self.pump() assert self.rcv.credit == 10, self.rcv.credit assert self.rcv.queued == 1, self.rcv.queued c = self.rcv.current assert c.tag == "tag", c.tag assert self.rcv.advance() assert self.rcv.credit == 9, self.rcv.credit assert self.rcv.queued == 0, self.rcv.queued def _testBufferingOnClose(self, a, b): for i in range(10): d = self.snd.delivery("tag-%s" % i) assert d d.settle() self.pump() assert self.snd.queued == 10 endpoints = {"connection": (self.c1, self.c2), "session": (self.snd.session, self.rcv.session), "link": (self.snd, self.rcv)} local_a, remote_a = endpoints[a] local_b, remote_b = endpoints[b] remote_b.close() self.pump() assert local_b.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED local_a.close() self.pump() assert remote_a.state & Endpoint.REMOTE_CLOSED assert self.snd.queued == 10 def testBufferingOnCloseLinkLink(self): self._testBufferingOnClose("link", "link") def testBufferingOnCloseLinkSession(self): self._testBufferingOnClose("link", "session") def testBufferingOnCloseLinkConnection(self): self._testBufferingOnClose("link", "connection") def testBufferingOnCloseSessionLink(self): self._testBufferingOnClose("session", "link") def testBufferingOnCloseSessionSession(self): self._testBufferingOnClose("session", "session") def testBufferingOnCloseSessionConnection(self): self._testBufferingOnClose("session", "connection") def testBufferingOnCloseConnectionLink(self): self._testBufferingOnClose("connection", "link") def testBufferingOnCloseConnectionSession(self): self._testBufferingOnClose("connection", "session") def testBufferingOnCloseConnectionConnection(self): self._testBufferingOnClose("connection", "connection") def testFullDrain(self): assert self.rcv.credit == 0 assert self.snd.credit == 0 self.rcv.drain(10) assert self.rcv.draining() assert self.rcv.credit == 10 assert self.snd.credit == 0 self.pump() assert self.rcv.credit == 10 assert self.snd.credit == 10 assert self.rcv.draining() self.snd.drained() assert self.rcv.credit == 10 assert self.snd.credit == 0 assert self.rcv.draining() self.pump() assert self.rcv.credit == 0 assert self.snd.credit == 0 assert not self.rcv.draining() drained = self.rcv.drained() assert drained == 10, drained def testPartialDrain(self): self.rcv.drain(2) assert self.rcv.draining() self.pump() d = self.snd.delivery("tag") assert d assert self.snd.advance() self.snd.drained() assert self.rcv.draining() self.pump() assert not self.rcv.draining() c = self.rcv.current assert self.rcv.queued == 1, self.rcv.queued assert c.tag == d.tag, c.tag assert self.rcv.advance() assert not self.rcv.current assert self.rcv.credit == 0, self.rcv.credit assert not self.rcv.draining() drained = self.rcv.drained() assert drained == 1, drained def testDrainFlow(self): assert self.rcv.credit == 0 assert self.snd.credit == 0 self.rcv.drain(10) assert self.rcv.credit == 10 assert self.snd.credit == 0 self.pump() assert self.rcv.credit == 10 assert self.snd.credit == 10 self.snd.drained() assert self.rcv.credit == 10 assert self.snd.credit == 0 self.pump() assert self.rcv.credit == 0 assert self.snd.credit == 0 self.rcv.flow(10) assert self.rcv.credit == 10 assert self.snd.credit == 0 self.pump() assert self.rcv.credit == 10 assert self.snd.credit == 10 self.snd.drained() assert self.rcv.credit == 10 assert self.snd.credit == 10 self.pump() assert self.rcv.credit == 10 assert self.snd.credit == 10 drained = self.rcv.drained() assert drained == 10, drained def testNegative(self): assert self.snd.credit == 0 d = self.snd.delivery("tag") assert d assert self.snd.advance() self.pump() assert self.rcv.credit == 0 assert self.rcv.queued == 0 self.rcv.flow(1) assert self.rcv.credit == 1 assert self.rcv.queued == 0 self.pump() assert self.rcv.credit == 1 assert self.rcv.queued == 1, self.rcv.queued c = self.rcv.current assert c assert c.tag == "tag" assert self.rcv.advance() assert self.rcv.credit == 0 assert self.rcv.queued == 0 def testDrainZero(self): assert self.snd.credit == 0 assert self.rcv.credit == 0 assert self.rcv.queued == 0 drained = self.rcv.drained() assert drained == 0 self.rcv.flow(10) self.pump() assert self.snd.credit == 10 assert self.rcv.credit == 10 assert self.rcv.queued == 0 self.snd.drained() self.pump() assert self.snd.credit == 10 assert self.rcv.credit == 10 assert self.rcv.queued == 0 drained = self.rcv.drained() assert drained == 0 self.rcv.drain(0) assert self.snd.credit == 10 assert self.rcv.credit == 10 assert self.rcv.queued == 0 self.pump() assert self.snd.credit == 10 assert self.rcv.credit == 10 assert self.rcv.queued == 0 self.snd.drained() assert self.snd.credit == 0 assert self.rcv.credit == 10 assert self.rcv.queued == 0 drained = self.rcv.drained() assert drained == 0 self.pump() assert self.snd.credit == 0 assert self.rcv.credit == 0 assert self.rcv.queued == 0 drained = self.rcv.drained() assert drained == 10 def testDrainOrder(self): """ Verify drain/drained works regardless of ordering. See PROTON-401 """ assert self.snd.credit == 0 assert self.rcv.credit == 0 assert self.rcv.queued == 0 #self.rcv.session.connection.transport.trace(Transport.TRACE_FRM) #self.snd.session.connection.transport.trace(Transport.TRACE_FRM) ## verify that a sender that has reached the drain state will respond ## promptly to a drain issued by the peer. self.rcv.flow(10) self.pump() assert self.snd.credit == 10, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit sd = self.snd.delivery("tagA") assert sd n = self.snd.send(str2bin("A")) assert n == 1 self.pump() self.snd.advance() # done sending, so signal that we are drained: self.snd.drained() self.pump() assert self.snd.credit == 9, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit self.rcv.drain(0) self.pump() assert self.snd.credit == 9, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit data = self.rcv.recv(10) assert data == str2bin("A"), data self.rcv.advance() self.pump() assert self.snd.credit == 9, self.snd.credit assert self.rcv.credit == 9, self.rcv.credit self.snd.drained() self.pump() assert self.snd.credit == 0, self.snd.credit assert self.rcv.credit == 0, self.rcv.credit # verify that a drain requested by the peer is not "acknowledged" until # after the sender has completed sending its pending messages self.rcv.flow(10) self.pump() assert self.snd.credit == 10, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit sd = self.snd.delivery("tagB") assert sd n = self.snd.send(str2bin("B")) assert n == 1 self.snd.advance() self.pump() assert self.snd.credit == 9, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit self.rcv.drain(0) self.pump() assert self.snd.credit == 9, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit sd = self.snd.delivery("tagC") assert sd n = self.snd.send(str2bin("C")) assert n == 1 self.snd.advance() self.pump() assert self.snd.credit == 8, self.snd.credit assert self.rcv.credit == 10, self.rcv.credit # now that the sender has finished sending everything, it can signal # drained self.snd.drained() self.pump() assert self.snd.credit == 0, self.snd.credit assert self.rcv.credit == 2, self.rcv.credit data = self.rcv.recv(10) assert data == str2bin("B"), data self.rcv.advance() data = self.rcv.recv(10) assert data == str2bin("C"), data self.rcv.advance() self.pump() assert self.snd.credit == 0, self.snd.credit assert self.rcv.credit == 0, self.rcv.credit def testPushback(self, count=10): assert self.snd.credit == 0 assert self.rcv.credit == 0 self.rcv.flow(count) self.pump() for i in range(count): d = self.snd.delivery("tag%s" % i) assert d self.snd.advance() assert self.snd.queued == count assert self.rcv.queued == 0 self.pump() assert self.snd.queued == 0 assert self.rcv.queued == count d = self.snd.delivery("extra") self.snd.advance() assert self.snd.queued == 1 assert self.rcv.queued == count self.pump() assert self.snd.queued == 1 assert self.rcv.queued == count def testHeadOfLineBlocking(self): self.snd2 = self.snd.session.sender("link-2") self.rcv2 = self.rcv.session.receiver("link-2") self.snd2.open() self.rcv2.open() self.pump() assert self.snd2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE assert self.rcv2.state == Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE self.rcv.flow(5) self.rcv2.flow(10) self.pump() assert self.snd.credit == 5 assert self.snd2.credit == 10 for i in range(10): tag = "test %d" % i self.snd.delivery( tag ) self.snd.send( tag.encode("ascii") ) assert self.snd.advance() self.snd2.delivery( tag ) self.snd2.send( tag.encode("ascii") ) assert self.snd2.advance() self.pump() for i in range(5): b = self.rcv.recv( 512 ) assert self.rcv.advance() b = self.rcv2.recv( 512 ) assert self.rcv2.advance() for i in range(5): b = self.rcv2.recv( 512 ) assert self.rcv2.advance() class SessionCreditTest(Test): def tearDown(self): self.cleanup() def testBuffering(self, count=32, size=1024, capacity=16*1024, max_frame=1024): snd, rcv = self.link("test-link", max_frame=(max_frame, max_frame)) rcv.session.incoming_capacity = capacity snd.open() rcv.open() rcv.flow(count) self.pump() assert count > 0 total_bytes = count * size assert snd.session.outgoing_bytes == 0, snd.session.outgoing_bytes assert rcv.session.incoming_bytes == 0, rcv.session.incoming_bytes assert snd.queued == 0, snd.queued assert rcv.queued == 0, rcv.queued data = bytes(bytearray(size)) idx = 0 while snd.credit: d = snd.delivery("tag%s" % idx) assert d n = snd.send(data) assert n == size, (n, size) assert snd.advance() self.pump() idx += 1 assert idx == count, (idx, count) assert snd.session.outgoing_bytes < total_bytes, (snd.session.outgoing_bytes, total_bytes) assert rcv.session.incoming_bytes < capacity, (rcv.session.incoming_bytes, capacity) assert snd.session.outgoing_bytes + rcv.session.incoming_bytes == total_bytes, \ (snd.session.outgoing_bytes, rcv.session.incoming_bytes, total_bytes) if snd.session.outgoing_bytes > 0: available = rcv.session.incoming_capacity - rcv.session.incoming_bytes assert available < max_frame, (available, max_frame) for i in range(count): d = rcv.current assert d, i pending = d.pending before = rcv.session.incoming_bytes assert rcv.advance() after = rcv.session.incoming_bytes assert before - after == pending, (before, after, pending) snd_before = snd.session.incoming_bytes self.pump() snd_after = snd.session.incoming_bytes assert rcv.session.incoming_bytes < capacity if snd_before > 0: assert capacity - after <= max_frame assert snd_before > snd_after if snd_after > 0: available = rcv.session.incoming_capacity - rcv.session.incoming_bytes assert available < max_frame, available def testBufferingSize16(self): self.testBuffering(size=16) def testBufferingSize256(self): self.testBuffering(size=256) def testBufferingSize512(self): self.testBuffering(size=512) def testBufferingSize2048(self): self.testBuffering(size=2048) def testBufferingSize1025(self): self.testBuffering(size=1025) def testBufferingSize1023(self): self.testBuffering(size=1023) def testBufferingSize989(self): self.testBuffering(size=989) def testBufferingSize1059(self): self.testBuffering(size=1059) def testCreditWithBuffering(self): snd, rcv = self.link("test-link", max_frame=(1024, 1024)) rcv.session.incoming_capacity = 64*1024 snd.open() rcv.open() rcv.flow(128) self.pump() assert snd.credit == 128, snd.credit assert rcv.queued == 0, rcv.queued idx = 0 while snd.credit: d = snd.delivery("tag%s" % idx) snd.send(("x"*1024).encode('ascii')) assert d assert snd.advance() self.pump() idx += 1 assert idx == 128, idx assert rcv.queued < 128, rcv.queued rcv.flow(1) self.pump() assert snd.credit == 1, snd.credit class SettlementTest(Test): def setUp(self): self.snd, self.rcv = self.link("test-link") self.c1 = self.snd.session.connection self.c2 = self.rcv.session.connection self.snd.open() self.rcv.open() self.pump() def cleanup(self): # release resources created by this class super(SettlementTest, self).cleanup() self.c1 = None self.snd = None self.c2 = None self.rcv2 = None self.snd2 = None def tearDown(self): self.cleanup() def testSettleCurrent(self): self.rcv.flow(10) self.pump() assert self.snd.credit == 10, self.snd.credit d = self.snd.delivery("tag") e = self.snd.delivery("tag2") assert d assert e c = self.snd.current assert c.tag == "tag", c.tag c.settle() c = self.snd.current assert c.tag == "tag2", c.tag c.settle() c = self.snd.current assert not c self.pump() c = self.rcv.current assert c assert c.tag == "tag", c.tag assert c.settled c.settle() c = self.rcv.current assert c assert c.tag == "tag2", c.tag assert c.settled c.settle() c = self.rcv.current assert not c def testUnsettled(self): self.rcv.flow(10) self.pump() assert self.snd.unsettled == 0, self.snd.unsettled assert self.rcv.unsettled == 0, self.rcv.unsettled d = self.snd.delivery("tag") assert d assert self.snd.unsettled == 1, self.snd.unsettled assert self.rcv.unsettled == 0, self.rcv.unsettled assert self.snd.advance() self.pump() assert self.snd.unsettled == 1, self.snd.unsettled assert self.rcv.unsettled == 1, self.rcv.unsettled c = self.rcv.current assert c c.settle() assert self.snd.unsettled == 1, self.snd.unsettled assert self.rcv.unsettled == 0, self.rcv.unsettled def testMultipleUnsettled(self, count=1024, size=1024): self.rcv.flow(count) self.pump() assert self.snd.unsettled == 0, self.snd.unsettled assert self.rcv.unsettled == 0, self.rcv.unsettled unsettled = [] for i in range(count): sd = self.snd.delivery("tag%s" % i) assert sd n = self.snd.send(("x"*size).encode('ascii')) assert n == size, n assert self.snd.advance() self.pump() rd = self.rcv.current assert rd, "did not receive delivery %s" % i n = rd.pending b = self.rcv.recv(n) assert len(b) == n, (b, n) rd.update(Delivery.ACCEPTED) assert self.rcv.advance() self.pump() unsettled.append(rd) assert self.rcv.unsettled == count for rd in unsettled: rd.settle() def testMultipleUnsettled2K1K(self): self.testMultipleUnsettled(2048, 1024) def testMultipleUnsettled4K1K(self): self.testMultipleUnsettled(4096, 1024) def testMultipleUnsettled1K2K(self): self.testMultipleUnsettled(1024, 2048) def testMultipleUnsettled2K2K(self): self.testMultipleUnsettled(2048, 2048) def testMultipleUnsettled4K2K(self): self.testMultipleUnsettled(4096, 2048) class PipelineTest(Test): def setUp(self): self.c1, self.c2 = self.connection() def cleanup(self): # release resources created by this class super(PipelineTest, self).cleanup() self.c1 = None self.c2 = None def tearDown(self): self.cleanup() def test(self): ssn = self.c1.session() snd = ssn.sender("sender") self.c1.open() ssn.open() snd.open() for i in range(10): d = snd.delivery("delivery-%s" % i) snd.send(str2bin("delivery-%s" % i)) d.settle() snd.close() ssn.close() self.c1.close() self.pump() state = self.c2.state assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state ssn2 = self.c2.session_head(Endpoint.LOCAL_UNINIT) assert ssn2 state == ssn2.state assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state rcv = self.c2.link_head(Endpoint.LOCAL_UNINIT) assert rcv state = rcv.state assert state == (Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_ACTIVE), "%x" % state self.c2.open() ssn2.open() rcv.open() rcv.flow(10) assert rcv.queued == 0, rcv.queued self.pump() assert rcv.queued == 10, rcv.queued state = rcv.state assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state state = ssn2.state assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state state = self.c2.state assert state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_CLOSED), "%x" % state for i in range(rcv.queued): d = rcv.current assert d assert d.tag == "delivery-%s" % i d.settle() assert rcv.queued == 0, rcv.queued class ServerTest(Test): def testKeepalive(self): """ Verify that idle frames are sent to keep a Connection alive """ if "java" in sys.platform: raise Skipped() idle_timeout = self.delay server = common.TestServer() server.start() class Program: def on_reactor_init(self, event): self.conn = event.reactor.connection() self.conn.hostname = "%s:%s" % (server.host, server.port) self.conn.open() self.old_count = None event.reactor.schedule(3 * idle_timeout, self) def on_connection_bound(self, event): event.transport.idle_timeout = idle_timeout def on_connection_remote_open(self, event): self.old_count = event.transport.frames_input def on_timer_task(self, event): assert self.conn.state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE), "Connection terminated" assert self.conn.transport.frames_input > self.old_count, "No idle frames received" self.conn.close() Reactor(Program()).run() server.stop() def testIdleTimeout(self): """ Verify that a Connection is terminated properly when Idle frames do not arrive in a timely manner. """ if "java" in sys.platform: raise Skipped() idle_timeout = self.delay server = common.TestServer(idle_timeout=idle_timeout) server.start() class Program: def on_reactor_init(self, event): self.conn = event.reactor.connection() self.conn.hostname = "%s:%s" % (server.host, server.port) self.conn.open() self.remote_condition = None self.old_count = None # verify the connection stays up even if we don't explicitly send stuff # wait up to 3x the idle timeout event.reactor.schedule(3 * idle_timeout, self) def on_connection_bound(self, event): self.transport = event.transport def on_connection_remote_open(self, event): self.old_count = event.transport.frames_output def on_connection_remote_close(self, event): assert self.conn.remote_condition assert self.conn.remote_condition.name == "amqp:resource-limit-exceeded" self.remote_condition = self.conn.remote_condition def on_timer_task(self, event): assert self.conn.state == (Endpoint.LOCAL_ACTIVE | Endpoint.REMOTE_ACTIVE), "Connection terminated" assert self.conn.transport.frames_output > self.old_count, "No idle frames sent" # now wait to explicitly cause the other side to expire: suspend_time = 3 * idle_timeout if os.name=="nt": # On windows, the full delay gets too close to the graceful/hard close tipping point suspend_time = 2.5 * idle_timeout sleep(suspend_time) p = Program() Reactor(p).run() assert p.remote_condition assert p.remote_condition.name == "amqp:resource-limit-exceeded" server.stop() class NoValue: def __init__(self): pass def apply(self, dlv): pass def check(self, dlv): assert dlv.data == None assert dlv.section_number == 0 assert dlv.section_offset == 0 assert dlv.condition == None assert dlv.failed == False assert dlv.undeliverable == False assert dlv.annotations == None class RejectValue: def __init__(self, condition): self.condition = condition def apply(self, dlv): dlv.condition = self.condition def check(self, dlv): assert dlv.data == None, dlv.data assert dlv.section_number == 0 assert dlv.section_offset == 0 assert dlv.condition == self.condition, (dlv.condition, self.condition) assert dlv.failed == False assert dlv.undeliverable == False assert dlv.annotations == None class ReceivedValue: def __init__(self, section_number, section_offset): self.section_number = section_number self.section_offset = section_offset def apply(self, dlv): dlv.section_number = self.section_number dlv.section_offset = self.section_offset def check(self, dlv): assert dlv.data == None, dlv.data assert dlv.section_number == self.section_number, (dlv.section_number, self.section_number) assert dlv.section_offset == self.section_offset assert dlv.condition == None assert dlv.failed == False assert dlv.undeliverable == False assert dlv.annotations == None class ModifiedValue: def __init__(self, failed, undeliverable, annotations): self.failed = failed self.undeliverable = undeliverable self.annotations = annotations def apply(self, dlv): dlv.failed = self.failed dlv.undeliverable = self.undeliverable dlv.annotations = self.annotations def check(self, dlv): assert dlv.data == None, dlv.data assert dlv.section_number == 0 assert dlv.section_offset == 0 assert dlv.condition == None assert dlv.failed == self.failed assert dlv.undeliverable == self.undeliverable assert dlv.annotations == self.annotations, (dlv.annotations, self.annotations) class CustomValue: def __init__(self, data): self.data = data def apply(self, dlv): dlv.data = self.data def check(self, dlv): assert dlv.data == self.data, (dlv.data, self.data) assert dlv.section_number == 0 assert dlv.section_offset == 0 assert dlv.condition == None assert dlv.failed == False assert dlv.undeliverable == False assert dlv.annotations == None class DeliveryTest(Test): def tearDown(self): self.cleanup() def testDisposition(self, count=1, tag="tag%i", type=Delivery.ACCEPTED, value=NoValue()): snd, rcv = self.link("test-link") snd.open() rcv.open() snd_deliveries = [] for i in range(count): d = snd.delivery(tag % i) snd_deliveries.append(d) snd.advance() rcv.flow(count) self.pump() rcv_deliveries = [] for i in range(count): d = rcv.current assert d.tag == (tag % i) rcv_deliveries.append(d) rcv.advance() for d in rcv_deliveries: value.apply(d.local) d.update(type) self.pump() for d in snd_deliveries: assert d.remote_state == type assert d.remote.type == type value.check(d.remote) value.apply(d.local) d.update(type) self.pump() for d in rcv_deliveries: assert d.remote_state == type assert d.remote.type == type value.check(d.remote) for d in snd_deliveries: d.settle() self.pump() for d in rcv_deliveries: assert d.settled, d.settled d.settle() def testReceived(self): self.testDisposition(type=Disposition.RECEIVED, value=ReceivedValue(1, 2)) def testRejected(self): self.testDisposition(type=Disposition.REJECTED, value=RejectValue(Condition(symbol("foo")))) def testReleased(self): self.testDisposition(type=Disposition.RELEASED) def testModified(self): self.testDisposition(type=Disposition.MODIFIED, value=ModifiedValue(failed=True, undeliverable=True, annotations={"key": "value"})) def testCustom(self): self.testDisposition(type=0x12345, value=CustomValue([1, 2, 3])) class CollectorTest(Test): def setUp(self): self.collector = Collector() def drain(self): result = [] while True: e = self.collector.peek() if e: result.append(e) self.collector.pop() else: break return result def expect(self, *types): return self.expect_oneof(types) def expect_oneof(self, *sequences): events = self.drain() types = tuple([e.type for e in events]) for alternative in sequences: if types == alternative: if len(events) == 1: return events[0] elif len(events) > 1: return events else: return assert False, "actual events %s did not match any of the expected sequences: %s" % (events, sequences) def expect_until(self, *types): events = self.drain() etypes = tuple([e.type for e in events[-len(types):]]) assert etypes == types, "actual events %s did not end in expect sequence: %s" % (events, types) class EventTest(CollectorTest): def tearDown(self): self.cleanup() def testEndpointEvents(self): c1, c2 = self.connection() c1.collect(self.collector) self.expect(Event.CONNECTION_INIT) self.pump() self.expect() c2.open() self.pump() self.expect(Event.CONNECTION_REMOTE_OPEN) self.pump() self.expect() ssn = c2.session() snd = ssn.sender("sender") ssn.open() snd.open() self.expect() self.pump() self.expect(Event.SESSION_INIT, Event.SESSION_REMOTE_OPEN, Event.LINK_INIT, Event.LINK_REMOTE_OPEN) c1.open() ssn2 = c1.session() ssn2.open() rcv = ssn2.receiver("receiver") rcv.open() self.pump() self.expect(Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.SESSION_INIT, Event.SESSION_LOCAL_OPEN, Event.TRANSPORT, Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT) rcv.close() self.expect(Event.LINK_LOCAL_CLOSE, Event.TRANSPORT) self.pump() rcv.free() del rcv self.expect(Event.LINK_FINAL) ssn2.free() del ssn2 self.pump() c1.free() c1.transport.unbind() self.expect_oneof((Event.SESSION_FINAL, Event.LINK_FINAL, Event.SESSION_FINAL, Event.CONNECTION_UNBOUND, Event.CONNECTION_FINAL), (Event.CONNECTION_UNBOUND, Event.SESSION_FINAL, Event.LINK_FINAL, Event.SESSION_FINAL, Event.CONNECTION_FINAL)) def testConnectionINIT_FINAL(self): c = Connection() c.collect(self.collector) self.expect(Event.CONNECTION_INIT) c.free() self.expect(Event.CONNECTION_FINAL) def testSessionINIT_FINAL(self): c = Connection() c.collect(self.collector) self.expect(Event.CONNECTION_INIT) s = c.session() self.expect(Event.SESSION_INIT) s.free() self.expect(Event.SESSION_FINAL) c.free() self.expect(Event.CONNECTION_FINAL) def testLinkINIT_FINAL(self): c = Connection() c.collect(self.collector) self.expect(Event.CONNECTION_INIT) s = c.session() self.expect(Event.SESSION_INIT) r = s.receiver("asdf") self.expect(Event.LINK_INIT) r.free() self.expect(Event.LINK_FINAL) c.free() self.expect(Event.SESSION_FINAL, Event.CONNECTION_FINAL) def testFlowEvents(self): snd, rcv = self.link("test-link") snd.session.connection.collect(self.collector) rcv.open() rcv.flow(10) self.pump() self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT, Event.LINK_INIT, Event.LINK_REMOTE_OPEN, Event.LINK_FLOW) rcv.flow(10) self.pump() self.expect(Event.LINK_FLOW) return snd, rcv def testDeliveryEvents(self): snd, rcv = self.link("test-link") rcv.session.connection.collect(self.collector) rcv.open() rcv.flow(10) self.pump() self.expect(Event.CONNECTION_INIT, Event.SESSION_INIT, Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT) snd.delivery("delivery") snd.send(str2bin("Hello World!")) snd.advance() self.pump() self.expect() snd.open() self.pump() self.expect(Event.LINK_REMOTE_OPEN, Event.DELIVERY) rcv.session.connection.transport.unbind() rcv.session.connection.free() self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT, Event.LINK_FINAL, Event.SESSION_FINAL, Event.CONNECTION_FINAL) def testDeliveryEventsDisp(self): snd, rcv = self.testFlowEvents() snd.open() dlv = snd.delivery("delivery") snd.send(str2bin("Hello World!")) assert snd.advance() self.expect(Event.LINK_LOCAL_OPEN, Event.TRANSPORT) self.pump() self.expect(Event.LINK_FLOW) rdlv = rcv.current assert rdlv != None assert rdlv.tag == "delivery" rdlv.update(Delivery.ACCEPTED) self.pump() event = self.expect(Event.DELIVERY) assert event.context == dlv, (dlv, event.context) def testConnectionBOUND_UNBOUND(self): c = Connection() c.collect(self.collector) self.expect(Event.CONNECTION_INIT) t = Transport() t.bind(c) self.expect(Event.CONNECTION_BOUND) t.unbind() self.expect(Event.CONNECTION_UNBOUND, Event.TRANSPORT) def testTransportERROR_CLOSE(self): c = Connection() c.collect(self.collector) self.expect(Event.CONNECTION_INIT) t = Transport() t.bind(c) self.expect(Event.CONNECTION_BOUND) assert t.condition is None t.push(str2bin("asdf")) self.expect(Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED) assert t.condition is not None assert t.condition.name == "amqp:connection:framing-error" assert "AMQP header mismatch" in t.condition.description p = t.pending() assert p > 0 t.pop(p) self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testTransportCLOSED(self): c = Connection() c.collect(self.collector) self.expect(Event.CONNECTION_INIT) t = Transport() t.bind(c) c.open() self.expect(Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT) c2 = Connection() t2 = Transport() t2.bind(c2) c2.open() c2.close() pump(t, t2) self.expect(Event.CONNECTION_REMOTE_OPEN, Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED) c.close() pump(t, t2) self.expect(Event.CONNECTION_LOCAL_CLOSE, Event.TRANSPORT, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testLinkDetach(self): c1 = Connection() c1.collect(self.collector) t1 = Transport() t1.bind(c1) c1.open() s1 = c1.session() s1.open() l1 = s1.sender("asdf") l1.open() l1.detach() self.expect_until(Event.LINK_LOCAL_DETACH, Event.TRANSPORT) c2 = Connection() c2.collect(self.collector) t2 = Transport() t2.bind(c2) pump(t1, t2) self.expect_until(Event.LINK_REMOTE_DETACH) class PeerTest(CollectorTest): def setUp(self): CollectorTest.setUp(self) self.connection = Connection() self.connection.collect(self.collector) self.transport = Transport() self.transport.bind(self.connection) self.peer = Connection() self.peer_transport = Transport() self.peer_transport.bind(self.peer) self.peer_transport.trace(Transport.TRACE_OFF) def pump(self): pump(self.transport, self.peer_transport) class TeardownLeakTest(PeerTest): def doLeak(self, local, remote): self.connection.open() self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT) ssn = self.connection.session() ssn.open() self.expect(Event.SESSION_INIT, Event.SESSION_LOCAL_OPEN, Event.TRANSPORT) snd = ssn.sender("sender") snd.open() self.expect(Event.LINK_INIT, Event.LINK_LOCAL_OPEN, Event.TRANSPORT) self.pump() self.peer.open() self.peer.session_head(0).open() self.peer.link_head(0).open() self.pump() self.expect_oneof((Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN, Event.LINK_REMOTE_OPEN, Event.LINK_FLOW), (Event.CONNECTION_REMOTE_OPEN, Event.SESSION_REMOTE_OPEN, Event.LINK_REMOTE_OPEN)) if local: snd.close() # ha!! self.expect(Event.LINK_LOCAL_CLOSE, Event.TRANSPORT) ssn.close() self.expect(Event.SESSION_LOCAL_CLOSE, Event.TRANSPORT) self.connection.close() self.expect(Event.CONNECTION_LOCAL_CLOSE, Event.TRANSPORT) if remote: self.peer.link_head(0).close() # ha!! self.peer.session_head(0).close() self.peer.close() self.pump() if remote: self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.LINK_REMOTE_CLOSE, Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_CLOSED) else: self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.SESSION_REMOTE_CLOSE, Event.CONNECTION_REMOTE_CLOSE, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_CLOSED) self.connection.free() self.expect(Event.LINK_FINAL, Event.SESSION_FINAL) self.transport.unbind() self.expect(Event.CONNECTION_UNBOUND, Event.CONNECTION_FINAL) def testLocalRemoteLeak(self): self.doLeak(True, True) def testLocalLeak(self): self.doLeak(True, False) def testRemoteLeak(self): self.doLeak(False, True) def testLeak(self): self.doLeak(False, False) class IdleTimeoutEventTest(PeerTest): def half_pump(self): p = self.transport.pending() if p>0: self.transport.pop(p) def testTimeoutWithZombieServer(self, expectOpenCloseFrames=True): self.transport.idle_timeout = self.delay self.connection.open() self.half_pump() self.transport.tick(time()) sleep(self.delay*2) self.transport.tick(time()) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED) assert self.transport.capacity() < 0 if expectOpenCloseFrames: assert self.transport.pending() > 0 self.half_pump() self.expect(Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) assert self.transport.pending() < 0 def testTimeoutWithZombieServerAndSASL(self): sasl = self.transport.sasl() self.testTimeoutWithZombieServer(expectOpenCloseFrames=False) class DeliverySegFaultTest(Test): def testDeliveryAfterUnbind(self): conn = Connection() t = Transport() ssn = conn.session() snd = ssn.sender("sender") dlv = snd.delivery("tag") dlv.settle() del dlv t.bind(conn) t.unbind() dlv = snd.delivery("tag") class SaslEventTest(CollectorTest): def testAnonymousNoInitialResponse(self): if "java" in sys.platform: raise Skipped() conn = Connection() conn.collect(self.collector) transport = Transport(Transport.SERVER) transport.bind(conn) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND) transport.push(str2bin('AMQP\x03\x01\x00\x00\x00\x00\x00 \x02\x01\x00\x00\x00SA' '\xd0\x00\x00\x00\x10\x00\x00\x00\x02\xa3\tANONYMOUS@' 'AMQP\x00\x01\x00\x00')) self.expect(Event.TRANSPORT) for i in range(1024): p = transport.pending() self.drain() p = transport.pending() self.expect() def testPipelinedServerReadFirst(self): if "java" in sys.platform: raise Skipped() conn = Connection() conn.collect(self.collector) transport = Transport(Transport.CLIENT) s = transport.sasl() s.allowed_mechs("ANONYMOUS PLAIN") transport.bind(conn) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND) transport.push(str2bin( # SASL 'AMQP\x03\x01\x00\x00' # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]] '\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS' # @sasl-outcome(68) [code=0] '\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00' # AMQP 'AMQP\x00\x01\x00\x00' )) self.expect(Event.TRANSPORT) p = transport.pending() bytes = transport.peek(p) transport.pop(p) server = Transport(Transport.SERVER) server.push(bytes) assert s.outcome == SASL.OK assert server.sasl().outcome == SASL.OK def testPipelinedServerWriteFirst(self): if "java" in sys.platform: raise Skipped() conn = Connection() conn.collect(self.collector) transport = Transport(Transport.CLIENT) s = transport.sasl() s.allowed_mechs("ANONYMOUS") transport.bind(conn) p = transport.pending() bytes = transport.peek(p) transport.pop(p) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND) transport.push(str2bin( # SASL 'AMQP\x03\x01\x00\x00' # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]] '\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS' # @sasl-outcome(68) [code=0] '\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00' # AMQP 'AMQP\x00\x01\x00\x00' )) self.expect(Event.TRANSPORT) p = transport.pending() bytes = transport.peek(p) transport.pop(p) assert s.outcome == SASL.OK # XXX: the bytes above appear to be correct, but we don't get any # sort of event indicating that the transport is authenticated qpid-proton-0.14.0/tests/python/proton_tests/handler.py0000644000175000017500000000704212770711161022545 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import absolute_import import os, gc, traceback import sys from . import common from time import time, sleep from proton import * from .common import pump, Skipped from proton.reactor import Reactor CUSTOM = EventType("custom") class HandlerTest(common.Test): def test_reactorHandlerCycling(self, n=0): class CustomHandler(Handler): UNSET = 999999999 def __init__(self): self.offset = len(traceback.extract_stack()) def on_reactor_init(self, event): self.depth = len(traceback.extract_stack()) def reset(self): self.depth = self.UNSET @property def init_depth(self): d = self.depth - self.offset return d custom = CustomHandler() reactor = Reactor() reactor.handler = custom for i in range(n): h = reactor.handler reactor.handler = h custom.reset() reactor.run() assert custom.init_depth < 50, "Unexpectedly long traceback for a simple handler" def test_reactorHandlerCycling10k(self): self.test_reactorHandlerCycling(10000) def test_reactorHandlerCycling100(self): self.test_reactorHandlerCycling(100) def do_customEvent(self, reactor_handler, event_root): class CustomHandler: did_custom = False did_init = False def __init__(self, *handlers): self.handlers = handlers def on_reactor_init(self, event): self.did_init = True def on_custom(self, event): self.did_custom = True class CustomInvoker(CustomHandler): def on_reactor_init(self, event): h = event_root(event) event.dispatch(h, CUSTOM) self.did_init = True child = CustomInvoker() root = CustomHandler(child) reactor = Reactor() reactor_handler(reactor, root) reactor.run() assert root.did_init assert child.did_init assert root.did_custom assert child.did_custom def set_root(self, reactor, root): reactor.handler = root def add_root(self, reactor, root): reactor.handler.add(root) def append_root(self, reactor, root): reactor.handler.handlers.append(root) def event_root(self, event): return event.root def event_reactor_handler(self, event): return event.reactor.handler def test_set_handler(self): self.do_customEvent(self.set_root, self.event_reactor_handler) def test_add_handler(self): self.do_customEvent(self.add_root, self.event_reactor_handler) def test_append_handler(self): self.do_customEvent(self.append_root, self.event_reactor_handler) def test_set_root(self): self.do_customEvent(self.set_root, self.event_root) def test_add_root(self): self.do_customEvent(self.add_root, self.event_root) def test_append_root(self): self.do_customEvent(self.append_root, self.event_root) qpid-proton-0.14.0/tests/python/proton_tests/interop.py0000644000175000017500000001232712770711161022612 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 proton import * import os from . import common from proton._compat import str2bin def find_test_interop_dir(): """Walk up the directory tree to find the tests directory.""" f = os.path.dirname(os.path.abspath(__file__)) while f and os.path.basename(f) != "tests": f = os.path.dirname(f) f = os.path.join(f, "interop") if not os.path.isdir(f): raise Exception("Cannot find test/interop directory from "+__file__) return f test_interop_dir=find_test_interop_dir() class InteropTest(common.Test): def setUp(self): self.data = Data() self.message = Message() def tearDown(self): self.data = None def get_data(self, name): filename = os.path.join(test_interop_dir, name+".amqp") f = open(filename,"rb") try: return f.read() finally: f.close() def decode_data(self, encoded): buffer = encoded while buffer: n = self.data.decode(buffer) buffer = buffer[n:] self.data.rewind() def decode_data_file(self, name): encoded = self.get_data(name) self.decode_data(encoded) encoded_size = self.data.encoded_size() # Re-encode and verify pre-computed and actual encoded size match. reencoded = self.data.encode() assert encoded_size == len(reencoded), "%d != %d" % (encoded_size, len(reencoded)) def decode_message_file(self, name): self.message.decode(self.get_data(name)) body = self.message.body if str(type(body)) == "": body = body.array.tostring() self.decode_data(body) def assert_next(self, type, value): next_type = self.data.next() assert next_type == type, "Type mismatch: %s != %s"%( Data.type_names[next_type], Data.type_names[type]) next_value = self.data.get_object() assert next_value == value, "Value mismatch: %s != %s"%(next_value, value) def test_message(self): self.decode_message_file("message") self.assert_next(Data.STRING, "hello") assert self.data.next() is None def test_primitives(self): self.decode_data_file("primitives") self.assert_next(Data.BOOL, True) self.assert_next(Data.BOOL, False) self.assert_next(Data.UBYTE, 42) self.assert_next(Data.USHORT, 42) self.assert_next(Data.SHORT, -42) self.assert_next(Data.UINT, 12345) self.assert_next(Data.INT, -12345) self.assert_next(Data.ULONG, 12345) self.assert_next(Data.LONG, -12345) self.assert_next(Data.FLOAT, 0.125) self.assert_next(Data.DOUBLE, 0.125) assert self.data.next() is None def test_strings(self): self.decode_data_file("strings") self.assert_next(Data.BINARY, str2bin("abc\0defg")) self.assert_next(Data.STRING, "abcdefg") self.assert_next(Data.SYMBOL, "abcdefg") self.assert_next(Data.BINARY, str2bin("")) self.assert_next(Data.STRING, "") self.assert_next(Data.SYMBOL, "") assert self.data.next() is None def test_described(self): self.decode_data_file("described") self.assert_next(Data.DESCRIBED, Described("foo-descriptor", "foo-value")) self.data.exit() assert self.data.next() == Data.DESCRIBED self.data.enter() self.assert_next(Data.INT, 12) self.assert_next(Data.INT, 13) self.data.exit() assert self.data.next() is None def test_described_array(self): self.decode_data_file("described_array") self.assert_next(Data.ARRAY, Array("int-array", Data.INT, *range(0,10))) def test_arrays(self): self.decode_data_file("arrays") self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT, *range(0,100))) self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.STRING, *["a", "b", "c"])) self.assert_next(Data.ARRAY, Array(UNDESCRIBED, Data.INT)) assert self.data.next() is None def test_lists(self): self.decode_data_file("lists") self.assert_next(Data.LIST, [32, "foo", True]) self.assert_next(Data.LIST, []) assert self.data.next() is None def test_maps(self): self.decode_data_file("maps") self.assert_next(Data.MAP, {"one":1, "two":2, "three":3 }) self.assert_next(Data.MAP, {1:"one", 2:"two", 3:"three"}) self.assert_next(Data.MAP, {}) assert self.data.next() is None qpid-proton-0.14.0/tests/python/proton_tests/message.py0000644000175000017500000000754512770711161022564 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os from . import common from proton import * from proton._compat import str2bin try: from uuid import uuid4 except ImportError: from proton import uuid4 class Test(common.Test): def setUp(self): self.msg = Message() def tearDown(self): self.msg = None class AccessorsTest(Test): def _test(self, name, default, values): d = getattr(self.msg, name) assert d == default, (d, default) for v in values: setattr(self.msg, name, v) gotten = getattr(self.msg, name) assert gotten == v, gotten def _test_symbol(self, name): self._test(name, symbol(None), (symbol(u"abc.123.#$%"), symbol(u"hello.world"))) def _test_str(self, name): self._test(name, None, (u"asdf", u"fdsa", u"")) def _test_time(self, name): self._test(name, 0, (0, 123456789, 987654321)) def testId(self): self._test("id", None, ("bytes", None, 123, u"string", uuid4())) def testCorrelationId(self): self._test("correlation_id", None, ("bytes", None, 123, u"string", uuid4())) def testDurable(self): self._test("durable", False, (True, False)) def testPriority(self): self._test("priority", Message.DEFAULT_PRIORITY, range(0, 255)) def testTtl(self): self._test("ttl", 0, range(12345, 54321)) def testFirstAquirer(self): self._test("first_acquirer", False, (True, False)) def testDeliveryCount(self): self._test("delivery_count", 0, range(0, 1024)) def testUserId(self): self._test("user_id", str2bin(""), (str2bin("asdf"), str2bin("fdsa"), str2bin("asd\x00fdsa"), str2bin(""))) def testAddress(self): self._test_str("address") def testSubject(self): self._test_str("subject") def testReplyTo(self): self._test_str("reply_to") def testContentType(self): self._test_symbol("content_type") def testContentEncoding(self): self._test_symbol("content_encoding") def testExpiryTime(self): self._test_time("expiry_time") def testCreationTime(self): self._test_time("creation_time") def testGroupId(self): self._test_str("group_id") def testGroupSequence(self): self._test("group_sequence", 0, (0, -10, 10, 20, -20)) def testReplyToGroupId(self): self._test_str("reply_to_group_id") class CodecTest(Test): def testRoundTrip(self): self.msg.id = "asdf" self.msg.correlation_id = uuid4() self.msg.ttl = 3 self.msg.priority = 100 self.msg.address = "address" self.msg.subject = "subject" self.msg.body = 'Hello World!' data = self.msg.encode() msg2 = Message() msg2.decode(data) assert self.msg.id == msg2.id, (self.msg.id, msg2.id) assert self.msg.correlation_id == msg2.correlation_id, (self.msg.correlation_id, msg2.correlation_id) assert self.msg.ttl == msg2.ttl, (self.msg.ttl, msg2.ttl) assert self.msg.priority == msg2.priority, (self.msg.priority, msg2.priority) assert self.msg.address == msg2.address, (self.msg.address, msg2.address) assert self.msg.subject == msg2.subject, (self.msg.subject, msg2.subject) assert self.msg.body == msg2.body, (self.msg.body, msg2.body) qpid-proton-0.14.0/tests/python/proton_tests/messenger.py0000644000175000017500000007302412770711161023123 0ustar danieldanielfrom __future__ import absolute_import # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os, sys, traceback from . import common from proton import * from threading import Thread, Event from time import sleep, time from .common import Skipped class Test(common.Test): def setUp(self): self.server_credit = 10 self.server_received = 0 self.server_finite_credit = False self.server = Messenger("server") self.server.timeout = self.timeout self.server.start() self.server.subscribe("amqp://~127.0.0.1:12345") self.server_thread = Thread(name="server-thread", target=self.run_server) self.server_thread.daemon = True self.server_is_running_event = Event() self.running = True self.server_thread_started = False self.client = Messenger("client") self.client.timeout = self.timeout def start(self): self.server_thread_started = True self.server_thread.start() self.server_is_running_event.wait(self.timeout) self.client.start() def _safelyStopClient(self): self.server.interrupt() self.client.stop() self.client = None def tearDown(self): try: if self.running: if not self.server_thread_started: self.start() # send a message to cause the server to promptly exit self.running = False self._safelyStopClient() finally: self.server_thread.join(self.timeout) self.server = None REJECT_ME = "*REJECT-ME*" class MessengerTest(Test): def run_server(self): if self.server_finite_credit: self._run_server_finite_credit() else: self._run_server_recv() def _run_server_recv(self): """ Use recv() to replenish credit each time the server waits """ msg = Message() try: while self.running: self.server_is_running_event.set() try: self.server.recv(self.server_credit) self.process_incoming(msg) except Interrupt: pass finally: self.server.stop() self.running = False def _run_server_finite_credit(self): """ Grant credit once, process until credit runs out """ msg = Message() self.server_is_running_event.set() try: self.server.recv(self.server_credit) while self.running: try: # do not grant additional credit (eg. call recv()) self.process_incoming(msg) self.server.work() except Interrupt: break finally: self.server.stop() self.running = False def process_incoming(self, msg): while self.server.incoming: self.server.get(msg) self.server_received += 1 if msg.body == REJECT_ME: self.server.reject() else: self.server.accept() self.dispatch(msg) def dispatch(self, msg): if msg.reply_to: msg.address = msg.reply_to self.server.put(msg) self.server.settle() def testSendReceive(self, size=None, address_size=None): self.start() msg = Message() if address_size: msg.address="amqp://127.0.0.1:12345/%s" % ("x"*address_size) else: msg.address="amqp://127.0.0.1:12345" msg.reply_to = "~" msg.subject="Hello World!" body = "First the world, then the galaxy!" if size is not None: while len(body) < size: body = 2*body body = body[:size] msg.body = body self.client.put(msg) self.client.send() reply = Message() self.client.recv(1) assert self.client.incoming == 1, self.client.incoming self.client.get(reply) assert reply.subject == "Hello World!" rbod = reply.body assert rbod == body, (rbod, body) def testSendReceive1K(self): self.testSendReceive(1024) def testSendReceive2K(self): self.testSendReceive(2*1024) def testSendReceive4K(self): self.testSendReceive(4*1024) def testSendReceive10K(self): self.testSendReceive(10*1024) def testSendReceive100K(self): self.testSendReceive(100*1024) def testSendReceive1M(self): self.testSendReceive(1024*1024) def testSendReceiveLargeAddress(self): self.testSendReceive(address_size=2048) # PROTON-285 - prevent continually failing test def xtestSendBogus(self): self.start() msg = Message() msg.address="totally-bogus-address" try: self.client.put(msg) assert False, "Expecting MessengerException" except MessengerException: exc = sys.exc_info()[1] err = str(exc) assert "unable to send to address: totally-bogus-address" in err, err def testOutgoingWindow(self): self.server.incoming_window = 10 self.start() msg = Message() msg.address="amqp://127.0.0.1:12345" msg.subject="Hello World!" trackers = [] for i in range(10): trackers.append(self.client.put(msg)) self.client.send() for t in trackers: assert self.client.status(t) is None # reduce outgoing_window to 5 and then try to send 10 messages self.client.outgoing_window = 5 trackers = [] for i in range(10): trackers.append(self.client.put(msg)) for i in range(5): t = trackers[i] assert self.client.status(t) is None, (t, self.client.status(t)) for i in range(5, 10): t = trackers[i] assert self.client.status(t) is PENDING, (t, self.client.status(t)) self.client.send() for i in range(5): t = trackers[i] assert self.client.status(t) is None for i in range(5, 10): t = trackers[i] assert self.client.status(t) is ACCEPTED def testReject(self, process_incoming=None): if process_incoming: self.process_incoming = process_incoming self.server.incoming_window = 10 self.start() msg = Message() msg.address="amqp://127.0.0.1:12345" msg.subject="Hello World!" self.client.outgoing_window = 10 trackers = [] rejected = [] for i in range(10): if i == 5: msg.body = REJECT_ME else: msg.body = "Yay!" trackers.append(self.client.put(msg)) if msg.body == REJECT_ME: rejected.append(trackers[-1]) self.client.send() for t in trackers: if t in rejected: assert self.client.status(t) is REJECTED, (t, self.client.status(t)) else: assert self.client.status(t) is ACCEPTED, (t, self.client.status(t)) def testRejectIndividual(self): self.testReject(self.reject_individual) def reject_individual(self, msg): if self.server.incoming < 10: self.server.work(0) return while self.server.incoming: t = self.server.get(msg) if msg.body == REJECT_ME: self.server.reject(t) self.dispatch(msg) self.server.accept() def testIncomingWindow(self): self.server.incoming_window = 10 self.server.outgoing_window = 10 self.start() msg = Message() msg.address="amqp://127.0.0.1:12345" msg.reply_to = "~" msg.subject="Hello World!" self.client.outgoing_window = 10 trackers = [] for i in range(10): trackers.append(self.client.put(msg)) self.client.send() for t in trackers: assert self.client.status(t) is ACCEPTED, (t, self.client.status(t)) self.client.incoming_window = 10 remaining = 10 trackers = [] while remaining: self.client.recv(remaining) while self.client.incoming: t = self.client.get() trackers.append(t) self.client.accept(t) remaining -= 1 for t in trackers: assert self.client.status(t) is ACCEPTED, (t, self.client.status(t)) def testIncomingQueueBiggerThanWindow(self, size=10): self.server.outgoing_window = size self.client.incoming_window = size self.start() msg = Message() msg.address = "amqp://127.0.0.1:12345" msg.reply_to = "~" msg.subject = "Hello World!" for i in range(2*size): self.client.put(msg) trackers = [] while len(trackers) < 2*size: self.client.recv(2*size - len(trackers)) while self.client.incoming: t = self.client.get(msg) assert self.client.status(t) is SETTLED, (t, self.client.status(t)) trackers.append(t) for t in trackers[:size]: assert self.client.status(t) is None, (t, self.client.status(t)) for t in trackers[size:]: assert self.client.status(t) is SETTLED, (t, self.client.status(t)) self.client.accept() for t in trackers[:size]: assert self.client.status(t) is None, (t, self.client.status(t)) for t in trackers[size:]: assert self.client.status(t) is ACCEPTED, (t, self.client.status(t)) def testIncomingQueueBiggerThanSessionWindow(self): self.testIncomingQueueBiggerThanWindow(2048) def testBuffered(self): self.client.outgoing_window = 1000 self.client.incoming_window = 1000 self.start(); assert self.server_received == 0 buffering = 0 count = 100 for i in range(count): msg = Message() msg.address="amqp://127.0.0.1:12345" msg.subject="Hello World!" msg.body = "First the world, then the galaxy!" t = self.client.put(msg) buffered = self.client.buffered(t) # allow transition from False to True, but not back if buffered: buffering += 1 else: assert not buffering, ("saw %s buffered deliveries before?" % buffering) while self.client.outgoing: last = self.client.outgoing self.client.send() #print "sent ", last - self.client.outgoing assert self.server_received == count def test_proton222(self): self.start() msg = Message() msg.address="amqp://127.0.0.1:12345" msg.subject="Hello World!" msg.body = "First the world, then the galaxy!" assert self.server_received == 0 self.client.put(msg) self.client.send() # ensure the server got the message without requiring client to stop first deadline = time() + 10 while self.server_received == 0: assert time() < deadline, "Server did not receive message!" sleep(.1) assert self.server_received == 1 def testUnlimitedCredit(self): """ Bring up two links. Verify credit is granted to each link by transferring a message over each. """ self.server_credit = -1 self.start() msg = Message() msg.address="amqp://127.0.0.1:12345/XXX" msg.reply_to = "~" msg.subject="Hello World!" body = "First the world, then the galaxy!" msg.body = body self.client.put(msg) self.client.send() reply = Message() self.client.recv(1) assert self.client.incoming == 1 self.client.get(reply) assert reply.subject == "Hello World!" rbod = reply.body assert rbod == body, (rbod, body) msg = Message() msg.address="amqp://127.0.0.1:12345/YYY" msg.reply_to = "~" msg.subject="Hello World!" body = "First the world, then the galaxy!" msg.body = body self.client.put(msg) self.client.send() reply = Message() self.client.recv(1) assert self.client.incoming == 1 self.client.get(reply) assert reply.subject == "Hello World!" rbod = reply.body assert rbod == body, (rbod, body) def _DISABLE_test_proton268(self): """ Reproducer for JIRA Proton-268 """ """ DISABLED: Causes failure on Jenkins, appears to be unrelated to fix """ self.server_credit = 2048 self.start() msg = Message() msg.address="amqp://127.0.0.1:12345" msg.body = "X" * 1024 for x in range( 100 ): self.client.put( msg ) self.client.send() try: self.client.stop() except Timeout: assert False, "Timeout waiting for client stop()" # need to restart client, as tearDown() uses it to stop server self.client.start() def testRoute(self): # anonymous cipher not supported on Windows if os.name == "nt" or not common.isSSLPresent(): domain = "amqp" else: domain = "amqps" self.server.subscribe(domain + "://~0.0.0.0:12346") self.start() self.client.route("route1", "amqp://127.0.0.1:12345") self.client.route("route2", domain + "://127.0.0.1:12346") msg = Message() msg.address = "route1" msg.reply_to = "~" msg.body = "test" self.client.put(msg) self.client.recv(1) reply = Message() self.client.get(reply) msg = Message() msg.address = "route2" msg.reply_to = "~" msg.body = "test" self.client.put(msg) self.client.recv(1) self.client.get(reply) assert reply.body == "test" def testDefaultRoute(self): self.start() self.client.route("*", "amqp://127.0.0.1:12345") msg = Message() msg.address = "asdf" msg.body = "test" msg.reply_to = "~" self.client.put(msg) self.client.recv(1) reply = Message() self.client.get(reply) assert reply.body == "test" def testDefaultRouteSubstitution(self): self.start() self.client.route("*", "amqp://127.0.0.1:12345/$1") msg = Message() msg.address = "asdf" msg.body = "test" msg.reply_to = "~" self.client.put(msg) self.client.recv(1) reply = Message() self.client.get(reply) assert reply.body == "test" def testIncomingRoute(self): self.start() self.client.route("in", "amqp://~0.0.0.0:12346") self.client.subscribe("in") msg = Message() msg.address = "amqp://127.0.0.1:12345" msg.reply_to = "amqp://127.0.0.1:12346" msg.body = "test" self.client.put(msg) self.client.recv(1) reply = Message() self.client.get(reply) assert reply.body == "test" def echo_address(self, msg): while self.server.incoming: self.server.get(msg) msg.body = msg.address self.dispatch(msg) def _testRewrite(self, original, rewritten): self.start() self.process_incoming = self.echo_address self.client.route("*", "amqp://127.0.0.1:12345") msg = Message() msg.address = original msg.body = "test" msg.reply_to = "~" self.client.put(msg) assert msg.address == original self.client.recv(1) assert self.client.incoming == 1 echo = Message() self.client.get(echo) assert echo.body == rewritten, (echo.body, rewritten) assert msg.address == original def testDefaultRewriteH(self): self._testRewrite("original", "original") def testDefaultRewriteUH(self): self._testRewrite("user@original", "original") def testDefaultRewriteUPH(self): self._testRewrite("user:pass@original", "original") def testDefaultRewriteHP(self): self._testRewrite("original:123", "original:123") def testDefaultRewriteUHP(self): self._testRewrite("user@original:123", "original:123") def testDefaultRewriteUPHP(self): self._testRewrite("user:pass@original:123", "original:123") def testDefaultRewriteHN(self): self._testRewrite("original/name", "original/name") def testDefaultRewriteUHN(self): self._testRewrite("user@original/name", "original/name") def testDefaultRewriteUPHN(self): self._testRewrite("user:pass@original/name", "original/name") def testDefaultRewriteHPN(self): self._testRewrite("original:123/name", "original:123/name") def testDefaultRewriteUHPN(self): self._testRewrite("user@original:123/name", "original:123/name") def testDefaultRewriteUPHPN(self): self._testRewrite("user:pass@original:123/name", "original:123/name") def testDefaultRewriteSH(self): self._testRewrite("amqp://original", "amqp://original") def testDefaultRewriteSUH(self): self._testRewrite("amqp://user@original", "amqp://original") def testDefaultRewriteSUPH(self): self._testRewrite("amqp://user:pass@original", "amqp://original") def testDefaultRewriteSHP(self): self._testRewrite("amqp://original:123", "amqp://original:123") def testDefaultRewriteSUHP(self): self._testRewrite("amqp://user@original:123", "amqp://original:123") def testDefaultRewriteSUPHP(self): self._testRewrite("amqp://user:pass@original:123", "amqp://original:123") def testDefaultRewriteSHN(self): self._testRewrite("amqp://original/name", "amqp://original/name") def testDefaultRewriteSUHN(self): self._testRewrite("amqp://user@original/name", "amqp://original/name") def testDefaultRewriteSUPHN(self): self._testRewrite("amqp://user:pass@original/name", "amqp://original/name") def testDefaultRewriteSHPN(self): self._testRewrite("amqp://original:123/name", "amqp://original:123/name") def testDefaultRewriteSUHPN(self): self._testRewrite("amqp://user@original:123/name", "amqp://original:123/name") def testDefaultRewriteSUPHPN(self): self._testRewrite("amqp://user:pass@original:123/name", "amqp://original:123/name") def testRewriteSupress(self): self.client.rewrite("*", None) self._testRewrite("asdf", None) def testRewrite(self): self.client.rewrite("a", "b") self._testRewrite("a", "b") def testRewritePattern(self): self.client.rewrite("amqp://%@*", "amqp://$2") self._testRewrite("amqp://foo@bar", "amqp://bar") def testRewriteToAt(self): self.client.rewrite("amqp://%/*", "$2@$1") self._testRewrite("amqp://domain/name", "name@domain") def testRewriteOverrideDefault(self): self.client.rewrite("*", "$1") self._testRewrite("amqp://user:pass@host", "amqp://user:pass@host") def testCreditBlockingRebalance(self): """ The server is given a fixed amount of credit, and runs until that credit is exhausted. """ self.server_finite_credit = True self.server_credit = 11 self.start() # put one message out on "Link1" - since there are no other links, it # should get all the credit (10 after sending) msg = Message() msg.address="amqp://127.0.0.1:12345/Link1" msg.subject="Hello World!" body = "First the world, then the galaxy!" msg.body = body msg.reply_to = "~" self.client.put(msg) self.client.send() self.client.recv(1) assert self.client.incoming == 1 # Now attempt to exhaust credit using a different link for i in range(10): msg.address="amqp://127.0.0.1:12345/Link2" self.client.put(msg) self.client.send() deadline = time() + self.timeout count = 0 while count < 11 and time() < deadline: self.client.recv(-1) while self.client.incoming: self.client.get(msg) count += 1 assert count == 11, count # now attempt to send one more. There isn't enough credit, so it should # not be sent self.client.timeout = 1 msg.address="amqp://127.0.0.1:12345/Link2" self.client.put(msg) try: self.client.send() assert False, "expected client to time out in send()" except Timeout: pass assert self.client.outgoing == 1 class NBMessengerTest(common.Test): def setUp(self): self.client = Messenger("client") self.client2 = Messenger("client2") self.server = Messenger("server") self.messengers = [self.client, self.client2, self.server] self.client.blocking = False self.client2.blocking = False self.server.blocking = False self.server.start() self.client.start() self.client2.start() self.address = "amqp://127.0.0.1:12345" self.server.subscribe("amqp://~0.0.0.0:12345") def _pump(self, timeout, work_triggers_exit): for msgr in self.messengers: if msgr.work(timeout) and work_triggers_exit: return True return False def pump(self, timeout=0): while self._pump(0, True): pass self._pump(timeout, False) while self._pump(0, True): pass def tearDown(self): self.server.stop() self.client.stop() self.client2.stop() self.pump() assert self.server.stopped assert self.client.stopped assert self.client2.stopped def testSmoke(self, count=1): self.server.recv() msg = Message() msg.address = self.address for i in range(count): msg.body = "Hello %s" % i self.client.put(msg) msg2 = Message() for i in range(count): if self.server.incoming == 0: self.pump() assert self.server.incoming > 0, self.server.incoming self.server.get(msg2) assert msg2.body == "Hello %s" % i, (msg2.body, i) assert self.client.outgoing == 0, self.client.outgoing assert self.server.incoming == 0, self.client.incoming def testSmoke1024(self): self.testSmoke(1024) def testSmoke4096(self): self.testSmoke(4096) def testPushback(self): self.server.recv() msg = Message() msg.address = self.address for i in range(16): for i in range(1024): self.client.put(msg) self.pump() if self.client.outgoing > 0: break assert self.client.outgoing > 0 def testRecvBeforeSubscribe(self): self.client.recv() self.client.subscribe(self.address + "/foo") self.pump() msg = Message() msg.address = "amqp://client/foo" msg.body = "Hello World!" self.server.put(msg) assert self.client.incoming == 0 self.pump(self.delay) assert self.client.incoming == 1 msg2 = Message() self.client.get(msg2) assert msg2.address == msg.address assert msg2.body == msg.body def testCreditAutoBackpressure(self): """ Verify that use of automatic credit (pn_messenger_recv(-1)) does not fill the incoming queue indefinitely. If the receiver does not 'get' the message, eventually the sender will block. See PROTON-350 """ self.server.recv() msg = Message() msg.address = self.address deadline = time() + self.timeout while time() < deadline: old = self.server.incoming for j in range(1001): self.client.put(msg) self.pump() if old == self.server.incoming: break; assert old == self.server.incoming, "Backpressure not active!" def testCreditRedistribution(self): """ Verify that a fixed amount of credit will redistribute to new links. """ self.server.recv( 5 ) # first link will get all credit msg1 = Message() msg1.address = self.address + "/msg1" self.client.put(msg1) self.pump() assert self.server.incoming == 1, self.server.incoming assert self.server.receiving == 4, self.server.receiving # no credit left over for this link msg2 = Message() msg2.address = self.address + "/msg2" self.client.put(msg2) self.pump() assert self.server.incoming == 1, self.server.incoming assert self.server.receiving == 4, self.server.receiving # eventually, credit will rebalance and the new link will send deadline = time() + self.timeout while time() < deadline: sleep(.1) self.pump() if self.server.incoming == 2: break; assert self.server.incoming == 2, self.server.incoming assert self.server.receiving == 3, self.server.receiving def testCreditReclaim(self): """ Verify that credit is reclaimed when a link with outstanding credit is torn down. """ self.server.recv( 9 ) # first link will get all credit msg1 = Message() msg1.address = self.address + "/msg1" self.client.put(msg1) self.pump() assert self.server.incoming == 1, self.server.incoming assert self.server.receiving == 8, self.server.receiving # no credit left over for this link msg2 = Message() msg2.address = self.address + "/msg2" self.client.put(msg2) self.pump() assert self.server.incoming == 1, self.server.incoming assert self.server.receiving == 8, self.server.receiving # and none for this new client msg3 = Message() msg3.address = self.address + "/msg3" self.client2.put(msg3) self.pump() # eventually, credit will rebalance and all links will # send a message deadline = time() + self.timeout while time() < deadline: sleep(.1) self.pump() if self.server.incoming == 3: break; assert self.server.incoming == 3, self.server.incoming assert self.server.receiving == 6, self.server.receiving # now tear down client two, this should cause its outstanding credit to be # made available to the other links self.client2.stop() self.pump() for i in range(4): self.client.put(msg1) self.client.put(msg2) # should exhaust all credit deadline = time() + self.timeout while time() < deadline: sleep(.1) self.pump() if self.server.incoming == 9: break; assert self.server.incoming == 9, self.server.incoming assert self.server.receiving == 0, self.server.receiving def testCreditReplenish(self): """ When extra credit is available it should be granted to the first link that can use it. """ # create three links msg = Message() for i in range(3): msg.address = self.address + "/%d" % i self.client.put(msg) self.server.recv( 50 ) # 50/3 = 16 per link + 2 extra self.pump() assert self.server.incoming == 3, self.server.incoming assert self.server.receiving == 47, self.server.receiving # 47/3 = 15 per link, + 2 extra # verify one link can send 15 + the two extra (17) for i in range(17): msg.address = self.address + "/0" self.client.put(msg) self.pump() assert self.server.incoming == 20, self.server.incoming assert self.server.receiving == 30, self.server.receiving # now verify that the remaining credit (30) will eventually rebalance # across all links (10 per link) for j in range(10): for i in range(3): msg.address = self.address + "/%d" % i self.client.put(msg) deadline = time() + self.timeout while time() < deadline: sleep(.1) self.pump() if self.server.incoming == 50: break assert self.server.incoming == 50, self.server.incoming assert self.server.receiving == 0, self.server.receiving from select import select class Pump: def __init__(self, *messengers): self.messengers = messengers self.selectables = [] def pump_once(self): for m in self.messengers: while True: sel = m.selectable() if sel: self.selectables.append(sel) else: break reading = [] writing = [] for sel in self.selectables[:]: if sel.is_terminal: sel.release() self.selectables.remove(sel) else: if sel.reading: reading.append(sel) if sel.writing: writing.append(sel) readable, writable, _ = select(reading, writing, [], 0.1) count = 0 for s in readable: s.readable() count += 1 for s in writable: s.writable() count += 1 return count def pump(self): while self.pump_once(): pass class SelectableMessengerTest(common.Test): def testSelectable(self, count = 1): if os.name=="nt": # Conflict between native OS select() in Pump and IOCP based pn_selector_t # makes this fail on Windows (see PROTON-668). raise Skipped("Invalid test on Windows with IOCP.") mrcv = Messenger() mrcv.passive = True mrcv.subscribe("amqp://~0.0.0.0:1234") msnd = Messenger() msnd.passive = True m = Message() m.address = "amqp://127.0.0.1:1234" for i in range(count): m.body = u"Hello World! %s" % i msnd.put(m) p = Pump(msnd, mrcv) p.pump() assert msnd.outgoing == count assert mrcv.incoming == 0 mrcv.recv() mc = Message() try: for i in range(count): while mrcv.incoming == 0: p.pump() assert mrcv.incoming > 0, (count, msnd.outgoing, mrcv.incoming) mrcv.get(mc) assert mc.body == u"Hello World! %s" % i, (i, mc.body) finally: mrcv.stop() msnd.stop() assert not mrcv.stopped assert not msnd.stopped p.pump() assert mrcv.stopped assert msnd.stopped def testSelectable16(self): self.testSelectable(count=16) def testSelectable1024(self): self.testSelectable(count=1024) def testSelectable4096(self): self.testSelectable(count=4096) class IdleTimeoutTest(common.Test): def testIdleTimeout(self): """ Verify that a Messenger connection is kept alive using empty idle frames when a idle_timeout is advertised by the remote peer. """ if "java" in sys.platform: raise Skipped() idle_timeout_secs = self.delay try: idle_server = common.TestServer(idle_timeout=idle_timeout_secs) idle_server.timeout = self.timeout idle_server.start() idle_client = Messenger("idle_client") idle_client.timeout = self.timeout idle_client.start() idle_client.subscribe("amqp://%s:%s/foo" % (idle_server.host, idle_server.port)) idle_client.work(idle_timeout_secs/10) # wait up to 3x the idle timeout and hence verify that everything stays # connected during that time by virtue of no Exception being raised duration = 3 * idle_timeout_secs deadline = time() + duration while time() <= deadline: idle_client.work(idle_timeout_secs/10) continue # confirm link is still active assert not idle_server.conditions, idle_server.conditions finally: try: idle_client.stop() except: pass try: idle_server.stop() except: pass qpid-proton-0.14.0/tests/python/proton_tests/reactor.py0000644000175000017500000005111012770711161022562 0ustar danieldanielfrom __future__ import absolute_import # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import time import sys from .common import Test, SkipTest, TestServer, free_tcp_port, ensureCanTestExtendedSASL from proton.reactor import Container, Reactor, ApplicationEvent, EventInjector from proton.handlers import CHandshaker, MessagingHandler from proton import Handler, Url class Barf(Exception): pass class BarfOnInit: def on_reactor_init(self, event): raise Barf() def on_connection_init(self, event): raise Barf() def on_session_init(self, event): raise Barf() def on_link_init(self, event): raise Barf() class BarfOnTask: def on_timer_task(self, event): raise Barf() class BarfOnFinal: init = False def on_reactor_init(self, event): self.init = True def on_reactor_final(self, event): raise Barf() class BarfOnFinalDerived(CHandshaker): init = False def on_reactor_init(self, event): self.init = True def on_reactor_final(self, event): raise Barf() class ExceptionTest(Test): def setUp(self): self.reactor = Reactor() def test_reactor_final(self): self.reactor.global_handler = BarfOnFinal() try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_global_set(self): self.reactor.global_handler = BarfOnInit() try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_global_add(self): self.reactor.global_handler.add(BarfOnInit()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_reactor_set(self): self.reactor.handler = BarfOnInit() try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_reactor_add(self): self.reactor.handler.add(BarfOnInit()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_connection(self): self.reactor.connection(BarfOnInit()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_connection_set(self): c = self.reactor.connection() c.handler = BarfOnInit() try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_connection_add(self): c = self.reactor.connection() c.handler = object() c.handler.add(BarfOnInit()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_session_set(self): c = self.reactor.connection() s = c.session() s.handler = BarfOnInit() try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_session_add(self): c = self.reactor.connection() s = c.session() s.handler = object() s.handler.add(BarfOnInit()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_link_set(self): c = self.reactor.connection() s = c.session() l = s.sender("xxx") l.handler = BarfOnInit() try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_link_add(self): c = self.reactor.connection() s = c.session() l = s.sender("xxx") l.handler = object() l.handler.add(BarfOnInit()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_schedule(self): self.reactor.schedule(0, BarfOnTask()) try: self.reactor.run() assert False, "expected to barf" except Barf: pass def test_schedule_many_nothings(self): class Nothing: results = [] def on_timer_task(self, event): self.results.append(None) num = 12345 for a in range(num): self.reactor.schedule(0, Nothing()) self.reactor.run() assert len(Nothing.results) == num def test_schedule_many_nothing_refs(self): class Nothing: results = [] def on_timer_task(self, event): self.results.append(None) num = 12345 tasks = [] for a in range(num): tasks.append(self.reactor.schedule(0, Nothing())) self.reactor.run() assert len(Nothing.results) == num def test_schedule_many_nothing_refs_cancel_before_run(self): class Nothing: results = [] def on_timer_task(self, event): self.results.append(None) num = 12345 tasks = [] for a in range(num): tasks.append(self.reactor.schedule(0, Nothing())) for task in tasks: task.cancel() self.reactor.run() assert len(Nothing.results) == 0 def test_schedule_cancel(self): barf = self.reactor.schedule(10, BarfOnTask()) class CancelBarf: def __init__(self, barf): self.barf = barf def on_timer_task(self, event): self.barf.cancel() pass self.reactor.schedule(0, CancelBarf(barf)) now = self.reactor.mark() try: self.reactor.run() elapsed = self.reactor.mark() - now assert elapsed < 10, "expected cancelled task to not delay the reactor by %s" % elapsed except Barf: assert False, "expected barf to be cancelled" def test_schedule_cancel_many(self): num = 12345 barfs = set() for a in range(num): barf = self.reactor.schedule(10*(a+1), BarfOnTask()) class CancelBarf: def __init__(self, barf): self.barf = barf def on_timer_task(self, event): self.barf.cancel() barfs.discard(self.barf) pass self.reactor.schedule(0, CancelBarf(barf)) barfs.add(barf) now = self.reactor.mark() try: self.reactor.run() elapsed = self.reactor.mark() - now assert elapsed < num, "expected cancelled task to not delay the reactor by %s" % elapsed assert not barfs, "expected all barfs to be discarded" except Barf: assert False, "expected barf to be cancelled" class HandlerDerivationTest(Test): def setUp(self): import platform if platform.python_implementation() != "Jython": # Exception propagation does not work currently for CPython raise SkipTest() self.reactor = Reactor() def wrong_exception(self): import sys ex = sys.exc_info() assert False, " Unexpected exception " + str(ex[1]) def test_reactor_final_derived(self): h = BarfOnFinalDerived() self.reactor.global_handler = h try: self.reactor.run() assert False, "expected to barf" except Barf: pass except: self.wrong_exception() def test_reactor_final_py_child_py(self): class APoorExcuseForAHandler: def __init__(self): self.handlers = [BarfOnFinal()] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except Barf: pass except: self.wrong_exception() def test_reactor_final_py_child_derived(self): class APoorExcuseForAHandler: def __init__(self): self.handlers = [BarfOnFinalDerived()] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except Barf: pass except: self.wrong_exception() def test_reactor_final_derived_child_derived(self): class APoorExcuseForAHandler(CHandshaker): def __init__(self): CHandshaker.__init__(self) self.handlers = [BarfOnFinalDerived()] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except Barf: pass except: self.wrong_exception() def test_reactor_final_derived_child_py(self): class APoorExcuseForAHandler(CHandshaker): def __init__(self): CHandshaker.__init__(self) self.handlers = [BarfOnFinal()] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except Barf: pass except: self.wrong_exception() def test_reactor_init_derived(self): h = BarfOnFinalDerived() self.reactor.global_handler = h try: self.reactor.run() assert False, "expected to barf" except: assert h.init, "excpected the init" def test_reactor_init_py_child_py(self): h = BarfOnFinal() class APoorExcuseForAHandler: def __init__(self): self.handlers = [h] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except: assert h.init, "excpected the init" def test_reactor_init_py_child_derived(self): h = BarfOnFinalDerived() class APoorExcuseForAHandler: def __init__(self): self.handlers = [h] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except: assert h.init, "excpected the init" def test_reactor_init_derived_child_derived(self): h = BarfOnFinalDerived() class APoorExcuseForAHandler(CHandshaker): def __init__(self): CHandshaker.__init__(self) self.handlers = [h] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except: assert h.init, "excpected the init" def test_reactor_init_derived_child_py(self): h = BarfOnFinal() class APoorExcuseForAHandler(CHandshaker): def __init__(self): CHandshaker.__init__(self) self.handlers = [h] self.reactor.global_handler = APoorExcuseForAHandler() try: self.reactor.run() assert False, "expected to barf" except: assert h.init, "excpected the init" class ApplicationEventTest(Test): """Test application defined events and handlers.""" class MyTestServer(TestServer): def __init__(self): super(ApplicationEventTest.MyTestServer, self).__init__() class MyHandler(Handler): def __init__(self, test): super(ApplicationEventTest.MyHandler, self).__init__() self._test = test def on_hello(self, event): # verify PROTON-1056 self._test.hello_rcvd = str(event) def on_goodbye(self, event): self._test.goodbye_rcvd = str(event) def setUp(self): import os if not hasattr(os, 'pipe'): # KAG: seems like Jython doesn't have an os.pipe() method raise SkipTest() if os.name=="nt": # Correct implementation on Windows is complicated raise SkipTest("PROTON-1071") self.server = ApplicationEventTest.MyTestServer() self.server.reactor.handler.add(ApplicationEventTest.MyHandler(self)) self.event_injector = EventInjector() self.hello_event = ApplicationEvent("hello") self.goodbye_event = ApplicationEvent("goodbye") self.server.reactor.selectable(self.event_injector) self.hello_rcvd = None self.goodbye_rcvd = None self.server.start() def tearDown(self): self.server.stop() def _wait_for(self, predicate, timeout=10.0): deadline = time.time() + timeout while time.time() < deadline: if predicate(): break time.sleep(0.1) assert predicate() def test_application_events(self): self.event_injector.trigger(self.hello_event) self._wait_for(lambda: self.hello_rcvd is not None) self.event_injector.trigger(self.goodbye_event) self._wait_for(lambda: self.goodbye_rcvd is not None) class AuthenticationTestHandler(MessagingHandler): def __init__(self): super(AuthenticationTestHandler, self).__init__() port = free_tcp_port() self.url = "localhost:%i" % port self.verified = False def on_start(self, event): self.listener = event.container.listen(self.url) def on_connection_opened(self, event): event.connection.close() def on_connection_opening(self, event): assert event.connection.transport.user == "user@proton" self.verified = True def on_connection_closed(self, event): event.connection.close() self.listener.close() def on_connection_error(self, event): event.connection.close() self.listener.close() class ContainerTest(Test): """Test container subclass of reactor.""" def test_event_has_container_attribute(self): ensureCanTestExtendedSASL() class TestHandler(MessagingHandler): def __init__(self): super(TestHandler, self).__init__() port = free_tcp_port() self.url = "localhost:%i" % port def on_start(self, event): self.listener = event.container.listen(self.url) def on_connection_closing(self, event): event.connection.close() self.listener.close() test_handler = TestHandler() container = Container(test_handler) class ConnectionHandler(MessagingHandler): def __init__(self): super(ConnectionHandler, self).__init__() def on_connection_opened(self, event): event.connection.close() assert event.container == event.reactor assert event.container == container container.connect(test_handler.url, handler=ConnectionHandler()) container.run() def test_authentication_via_url(self): ensureCanTestExtendedSASL() test_handler = AuthenticationTestHandler() container = Container(test_handler) container.connect("%s:password@%s" % ("user%40proton", test_handler.url), reconnect=False) container.run() assert test_handler.verified def test_authentication_via_container_attributes(self): ensureCanTestExtendedSASL() test_handler = AuthenticationTestHandler() container = Container(test_handler) container.user = "user@proton" container.password = "password" container.connect(test_handler.url, reconnect=False) container.run() assert test_handler.verified def test_authentication_via_kwargs(self): ensureCanTestExtendedSASL() test_handler = AuthenticationTestHandler() container = Container(test_handler) container.connect(test_handler.url, user="user@proton", password="password", reconnect=False) container.run() assert test_handler.verified class _ServerHandler(MessagingHandler): def __init__(self, host): super(ContainerTest._ServerHandler, self).__init__() self.host = host port = free_tcp_port() self.port = free_tcp_port() self.client_addr = None self.peer_hostname = None def on_start(self, event): self.listener = event.container.listen("%s:%s" % (self.host, self.port)) def on_connection_opened(self, event): self.client_addr = event.reactor.get_connection_address(event.connection) self.peer_hostname = event.connection.remote_hostname def on_connection_closing(self, event): event.connection.close() self.listener.close() class _ClientHandler(MessagingHandler): def __init__(self): super(ContainerTest._ClientHandler, self).__init__() self.server_addr = None def on_connection_opened(self, event): self.server_addr = event.reactor.get_connection_address(event.connection) event.connection.close() def test_numeric_hostname(self): ensureCanTestExtendedSASL() server_handler = ContainerTest._ServerHandler("127.0.0.1") client_handler = ContainerTest._ClientHandler() container = Container(server_handler) container.connect(url=Url(host="127.0.0.1", port=server_handler.port), handler=client_handler) container.run() assert server_handler.client_addr assert client_handler.server_addr assert server_handler.peer_hostname == "127.0.0.1", server_handler.peer_hostname assert client_handler.server_addr.rsplit(':', 1)[1] == str(server_handler.port) def test_non_numeric_hostname(self): ensureCanTestExtendedSASL() server_handler = ContainerTest._ServerHandler("localhost") client_handler = ContainerTest._ClientHandler() container = Container(server_handler) container.connect(url=Url(host="localhost", port=server_handler.port), handler=client_handler) container.run() assert server_handler.client_addr assert client_handler.server_addr assert server_handler.peer_hostname == "localhost", server_handler.peer_hostname assert client_handler.server_addr.rsplit(':', 1)[1] == str(server_handler.port) def test_virtual_host(self): ensureCanTestExtendedSASL() server_handler = ContainerTest._ServerHandler("localhost") container = Container(server_handler) conn = container.connect(url=Url(host="localhost", port=server_handler.port), handler=ContainerTest._ClientHandler(), virtual_host="a.b.c.org") container.run() assert server_handler.peer_hostname == "a.b.c.org", server_handler.peer_hostname def test_no_virtual_host(self): # explicitly setting an empty virtual host should prevent the hostname # field from being sent in the Open performative if "java" in sys.platform: # This causes Python Container to *not* set the connection virtual # host, so when proton-j sets up the connection the virtual host # seems to be unset and the URL's host is used (as expected). raise SkipTest("Does not apply for proton-j"); server_handler = ContainerTest._ServerHandler("localhost") container = Container(server_handler) conn = container.connect(url=Url(host="localhost", port=server_handler.port), handler=ContainerTest._ClientHandler(), virtual_host="") container.run() assert server_handler.peer_hostname is None, server_handler.peer_hostname qpid-proton-0.14.0/tests/python/proton_tests/reactor_interop.py0000644000175000017500000001101612770711161024323 0ustar danieldaniel#!/usr/bin/python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import absolute_import from .common import Test, free_tcp_port, Skipped from proton import Message from proton.handlers import CHandshaker, CFlowController from proton.reactor import Reactor import os import subprocess from threading import Thread import time class JavaThread(Thread): def __init__(self, operation, port, count): Thread.__init__(self) self.operation = operation self.port = str(port) self.count = str(count) self.result = 1 def run(self): self.result = subprocess.call(['java', 'org.apache.qpid.proton.ProtonJInterop', self.operation, self.port, self.count]) class ReceiveHandler: def __init__(self, count): self.count = count self.handlers = [CHandshaker(), CFlowController()] self.messages = [] def on_reactor_init(self, event): port = free_tcp_port() self.acceptor = event.reactor.acceptor("127.0.0.1", port) self.java_thread = JavaThread("send", port, self.count) self.java_thread.start() def on_delivery(self, event): rcv = event.receiver msg = Message() if rcv and msg.recv(rcv): event.delivery.settle() self.messages += [msg.body] self.count -= 1 if (self.count == 0): self.acceptor.close() class SendHandler: def __init__(self, host, num_msgs): self.host = host self.num_msgs = num_msgs self.count = 0 self.handlers = [CHandshaker()] def on_connection_init(self, event): conn = event.connection conn.hostname = self.host ssn = conn.session() snd = ssn.sender("sender") conn.open() ssn.open() snd.open() def on_link_flow(self, event): snd = event.sender if snd.credit > 0 and self.count < self.num_msgs: self.count += 1 msg = Message("message-" + str(self.count)) dlv = snd.send(msg) dlv.settle() if (self.count == self.num_msgs): snd.close() snd.session.close() snd.connection.close() def on_reactor_init(self, event): event.reactor.connection(self) class ReactorInteropTest(Test): def setUp(self): classpath = "" if ('CLASSPATH' in os.environ): classpath = os.environ['CLASSPATH'] entries = classpath.split(os.pathsep) self.proton_j_available = False for entry in entries: self.proton_j_available |= entry != "" and os.path.exists(entry) def protonc_to_protonj(self, count): if (not self.proton_j_available): raise Skipped("ProtonJ not found") port = free_tcp_port() java_thread = JavaThread("recv", port, count) java_thread.start() # Give the Java thread time to spin up a JVM and start listening # XXX: would be better to parse the stdout output for a message time.sleep(1) sh = SendHandler('127.0.0.1:' + str(port), count) r = Reactor(sh) r.run() java_thread.join() assert(java_thread.result == 0) def protonj_to_protonc(self, count): if (not self.proton_j_available): raise Skipped("ProtonJ not found") rh = ReceiveHandler(count) r = Reactor(rh) r.run() rh.java_thread.join() assert(rh.java_thread.result == 0) for i in range(1, count): assert(rh.messages[i-1] == ("message-" + str(i))) def test_protonc_to_protonj_1(self): self.protonc_to_protonj(1) def test_protonc_to_protonj_5(self): self.protonc_to_protonj(5) def test_protonc_to_protonj_500(self): self.protonc_to_protonj(500) def test_protonc_to_protonj_5000(self): self.protonc_to_protonj(5000) def test_protonj_to_protonc_1(self): self.protonj_to_protonc(1) def test_protonj_to_protonc_5(self): self.protonj_to_protonc(5) def test_protonj_to_protonc_500(self): self.protonj_to_protonc(500) def test_protonj_to_protonc_5000(self): self.protonj_to_protonc(5000) qpid-proton-0.14.0/tests/python/proton_tests/sasl.py0000644000175000017500000005133612770711161022077 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import absolute_import import sys, os from . import common from . import engine from proton import * from .common import pump, Skipped from proton._compat import str2bin def _sslCertpath(file): """ Return the full path to the certificate,keyfile, etc. """ if os.name=="nt": if file.find("private-key")!=-1: # The private key is not in a separate store return None # Substitute pkcs#12 equivalent for the CA/key store if file.endswith(".pem"): file = file[:-4] + ".p12" return os.path.join(os.path.dirname(__file__), "ssl_db/%s" % file) def _testSaslMech(self, mech, clientUser='user@proton', authUser='user@proton', encrypted=False, authenticated=True): self.s1.allowed_mechs(mech) self.c1.open() self.c2.open() pump(self.t1, self.t2, 1024) if encrypted is not None: assert self.t2.encrypted == encrypted, encrypted assert self.t1.encrypted == encrypted, encrypted assert self.t2.authenticated == authenticated, authenticated assert self.t1.authenticated == authenticated, authenticated if authenticated: # Server assert self.t2.user == authUser assert self.s2.user == authUser assert self.s2.mech == mech.strip() assert self.s2.outcome == SASL.OK, self.s2.outcome assert self.c2.state & Endpoint.LOCAL_ACTIVE and self.c2.state & Endpoint.REMOTE_ACTIVE,\ "local_active=%s, remote_active=%s" % (self.c1.state & Endpoint.LOCAL_ACTIVE, self.c1.state & Endpoint.REMOTE_ACTIVE) # Client assert self.t1.user == clientUser assert self.s1.user == clientUser assert self.s1.mech == mech.strip() assert self.s1.outcome == SASL.OK, self.s1.outcome assert self.c1.state & Endpoint.LOCAL_ACTIVE and self.c1.state & Endpoint.REMOTE_ACTIVE,\ "local_active=%s, remote_active=%s" % (self.c1.state & Endpoint.LOCAL_ACTIVE, self.c1.state & Endpoint.REMOTE_ACTIVE) else: # Server assert self.t2.user == None assert self.s2.user == None assert self.s2.outcome != SASL.OK, self.s2.outcome # Client assert self.t1.user == clientUser assert self.s1.user == clientUser assert self.s1.outcome != SASL.OK, self.s1.outcome class Test(common.Test): pass def consumeAllOuput(t): stops = 0 while stops<1: out = t.peek(1024) l = len(out) if out else 0 t.pop(l) if l <= 0: stops += 1 class SaslTest(Test): def setUp(self): self.t1 = Transport() self.s1 = SASL(self.t1) self.t2 = Transport(Transport.SERVER) self.t2.max_frame_size = 65536 self.s2 = SASL(self.t2) def pump(self): pump(self.t1, self.t2, 1024) # We have to generate the client frames manually because proton does not # generate pipelined SASL and AMQP frames together def testIllegalProtocolLayering(self): # TODO: Skip Proton-J for now if "java" in sys.platform: raise Skipped("Proton-J does not set error condition on protocol layering violation") # Server self.s2.allowed_mechs('ANONYMOUS') c2 = Connection() self.t2.bind(c2) assert self.s2.outcome is None # Push client bytes into server self.t2.push(str2bin( # SASL 'AMQP\x03\x01\x00\x00' # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"] '\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia' # SASL (again illegally) 'AMQP\x03\x01\x00\x00' # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"] '\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia' # AMQP 'AMQP\x00\x01\x00\x00' # @open(16) [container-id="", channel-max=1234] '\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@' )) consumeAllOuput(self.t2) assert self.t2.condition assert self.t2.closed assert not c2.state & Endpoint.REMOTE_ACTIVE def testPipelinedClient(self): # TODO: When PROTON-1136 is fixed then remove this test if "java" in sys.platform: raise Skipped("Proton-J does not support pipelined client input") # Server self.s2.allowed_mechs('ANONYMOUS') c2 = Connection() self.t2.bind(c2) assert self.s2.outcome is None # Push client bytes into server self.t2.push(str2bin( # SASL 'AMQP\x03\x01\x00\x00' # @sasl-init(65) [mechanism=:ANONYMOUS, initial-response=b"anonymous@fuschia"] '\x00\x00\x002\x02\x01\x00\x00\x00SA\xd0\x00\x00\x00"\x00\x00\x00\x02\xa3\x09ANONYMOUS\xa0\x11anonymous@fuschia' # AMQP 'AMQP\x00\x01\x00\x00' # @open(16) [container-id="", channel-max=1234] '\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@' )) consumeAllOuput(self.t2) assert not self.t2.condition assert self.s2.outcome == SASL.OK assert c2.state & Endpoint.REMOTE_ACTIVE def testPipelinedServer(self): # Client self.s1.allowed_mechs('ANONYMOUS') c1 = Connection() self.t1.bind(c1) assert self.s1.outcome is None # Push server bytes into client # Commented out lines in this test are where the client input processing doesn't # run after output processing even though there is input waiting self.t1.push(str2bin( # SASL 'AMQP\x03\x01\x00\x00' # @sasl-mechanisms(64) [sasl-server-mechanisms=@PN_SYMBOL[:ANONYMOUS]] '\x00\x00\x00\x1c\x02\x01\x00\x00\x00S@\xc0\x0f\x01\xe0\x0c\x01\xa3\tANONYMOUS' # @sasl-outcome(68) [code=0] '\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00' # AMQP 'AMQP\x00\x01\x00\x00' # @open(16) [container-id="", channel-max=1234] '\x00\x00\x00!\x02\x00\x00\x00\x00S\x10\xd0\x00\x00\x00\x11\x00\x00\x00\x0a\xa1\x00@@`\x04\xd2@@@@@@' )) consumeAllOuput(self.t1) assert self.s1.outcome == SASL.OK assert c1.state & Endpoint.REMOTE_ACTIVE def testPipelined2(self): if "java" in sys.platform: raise Skipped("Proton-J does not support client pipelining") out1 = self.t1.peek(1024) self.t1.pop(len(out1)) self.t2.push(out1) self.s2.allowed_mechs('ANONYMOUS') c2 = Connection() c2.open() self.t2.bind(c2) out2 = self.t2.peek(1024) self.t2.pop(len(out2)) self.t1.push(out2) out1 = self.t1.peek(1024) assert len(out1) > 0 def testFracturedSASL(self): """ PROTON-235 """ assert self.s1.outcome is None # self.t1.trace(Transport.TRACE_FRM) out = self.t1.peek(1024) self.t1.pop(len(out)) self.t1.push(str2bin("AMQP\x03\x01\x00\x00")) out = self.t1.peek(1024) self.t1.pop(len(out)) self.t1.push(str2bin("\x00\x00\x00")) out = self.t1.peek(1024) self.t1.pop(len(out)) self.t1.push(str2bin("6\x02\x01\x00\x00\x00S@\xc04\x01\xe01\x04\xa3\x05PLAIN\x0aDIGEST-MD5\x09ANONYMOUS\x08CRAM-MD5")) out = self.t1.peek(1024) self.t1.pop(len(out)) self.t1.push(str2bin("\x00\x00\x00\x10\x02\x01\x00\x00\x00SD\xc0\x03\x01P\x00")) out = self.t1.peek(1024) self.t1.pop(len(out)) while out: out = self.t1.peek(1024) self.t1.pop(len(out)) assert self.s1.outcome == SASL.OK, self.s1.outcome def test_singleton(self): """Verify that only a single instance of SASL can exist per Transport""" transport = Transport() attr = object() sasl1 = SASL(transport) sasl1.my_attribute = attr sasl2 = transport.sasl() sasl3 = SASL(transport) assert sasl1 == sasl2 assert sasl1 == sasl3 assert sasl1.my_attribute == attr assert sasl2.my_attribute == attr assert sasl3.my_attribute == attr transport = Transport() sasl1 = transport.sasl() sasl1.my_attribute = attr sasl2 = SASL(transport) assert sasl1 == sasl2 assert sasl1.my_attribute == attr assert sasl2.my_attribute == attr def testSaslSkipped(self): """Verify that the server (with SASL) correctly handles a client without SASL""" self.t1 = Transport() self.t2.require_auth(False) self.pump() assert self.s2.outcome == None assert self.t2.condition == None assert self.t2.authenticated == False assert self.s1.outcome == None assert self.t1.condition == None assert self.t1.authenticated == False def testSaslSkippedFail(self): """Verify that the server (with SASL) correctly handles a client without SASL""" self.t1 = Transport() self.t2.require_auth(True) self.pump() assert self.s2.outcome == None assert self.t2.condition != None assert self.s1.outcome == None assert self.t1.condition != None def testMechNotFound(self): if "java" in sys.platform: raise Skipped("Proton-J does not support checking authentication state") self.c1 = Connection() self.c1.open() self.t1.bind(self.c1) self.s1.allowed_mechs('IMPOSSIBLE') self.pump() assert self.t2.authenticated == False assert self.t1.authenticated == False assert self.s1.outcome != SASL.OK assert self.s2.outcome != SASL.OK class SASLMechTest(Test): def setUp(self): self.t1 = Transport() self.s1 = SASL(self.t1) self.t2 = Transport(Transport.SERVER) self.s2 = SASL(self.t2) self.c1 = Connection() self.c1.user = 'user@proton' self.c1.password = 'password' self.c1.hostname = 'localhost' self.c2 = Connection() def testANON(self): self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'ANONYMOUS', authUser='anonymous') def testCRAMMD5(self): common.ensureCanTestExtendedSASL() self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'CRAM-MD5') def testDIGESTMD5(self): common.ensureCanTestExtendedSASL() self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5') # PLAIN shouldn't work without encryption without special setting def testPLAINfail(self): common.ensureCanTestExtendedSASL() self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'PLAIN', authenticated=False) # Client won't accept PLAIN even if offered by server without special setting def testPLAINClientFail(self): common.ensureCanTestExtendedSASL() self.s2.allow_insecure_mechs = True self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'PLAIN', authenticated=False) # PLAIN will only work if both ends are specially set up def testPLAIN(self): common.ensureCanTestExtendedSASL() self.s1.allow_insecure_mechs = True self.s2.allow_insecure_mechs = True self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'PLAIN') # SCRAM not supported before Cyrus SASL 2.1.26 # so not universal and hance need a test for support # to keep it in tests. # def testSCRAMSHA1(self): # common.ensureCanTestExtendedSASL() # # self.t1.bind(self.c1) # self.t2.bind(self.c2) # _testSaslMech(self, 'SCRAM-SHA-1') def _sslConnection(domain, transport, connection): transport.bind(connection) ssl = SSL(transport, domain, None ) return connection class SSLSASLTest(Test): def setUp(self): if not common.isSSLPresent(): raise Skipped("No SSL libraries found.") self.server_domain = SSLDomain(SSLDomain.MODE_SERVER) self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT) self.t1 = Transport() self.s1 = SASL(self.t1) self.t2 = Transport(Transport.SERVER) self.s2 = SASL(self.t2) self.c1 = Connection() self.c2 = Connection() def testSSLPlainSimple(self): if "java" in sys.platform: raise Skipped("Proton-J does not support SSL with SASL") if not SASL.extended(): raise Skipped("Simple SASL server does not support PLAIN") common.ensureCanTestExtendedSASL() clientUser = 'user@proton' mech = 'PLAIN' self.c1.user = clientUser self.c1.password = 'password' self.c1.hostname = 'localhost' ssl1 = _sslConnection(self.client_domain, self.t1, self.c1) ssl2 = _sslConnection(self.server_domain, self.t2, self.c2) _testSaslMech(self, mech, encrypted=True) def testSSLPlainSimpleFail(self): if "java" in sys.platform: raise Skipped("Proton-J does not support SSL with SASL") if not SASL.extended(): raise Skipped("Simple SASL server does not support PLAIN") common.ensureCanTestExtendedSASL() clientUser = 'usr@proton' mech = 'PLAIN' self.c1.user = clientUser self.c1.password = 'password' self.c1.hostname = 'localhost' ssl1 = _sslConnection(self.client_domain, self.t1, self.c1) ssl2 = _sslConnection(self.server_domain, self.t2, self.c2) _testSaslMech(self, mech, clientUser='usr@proton', encrypted=True, authenticated=False) def testSSLExternalSimple(self): if "java" in sys.platform: raise Skipped("Proton-J does not support SSL with SASL") if os.name=="nt": extUser = 'O=Client, CN=127.0.0.1' else: extUser = 'O=Client,CN=127.0.0.1' mech = 'EXTERNAL' self.server_domain.set_credentials(_sslCertpath("server-certificate.pem"), _sslCertpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem")) self.server_domain.set_peer_authentication(SSLDomain.VERIFY_PEER, _sslCertpath("ca-certificate.pem") ) self.client_domain.set_credentials(_sslCertpath("client-certificate.pem"), _sslCertpath("client-private-key.pem"), "client-password") self.client_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem")) self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER) ssl1 = _sslConnection(self.client_domain, self.t1, self.c1) ssl2 = _sslConnection(self.server_domain, self.t2, self.c2) _testSaslMech(self, mech, clientUser=None, authUser=extUser, encrypted=True) def testSSLExternalSimpleFail(self): if "java" in sys.platform: raise Skipped("Proton-J does not support SSL with SASL") mech = 'EXTERNAL' self.server_domain.set_credentials(_sslCertpath("server-certificate.pem"), _sslCertpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem")) self.server_domain.set_peer_authentication(SSLDomain.VERIFY_PEER, _sslCertpath("ca-certificate.pem") ) self.client_domain.set_trusted_ca_db(_sslCertpath("ca-certificate.pem")) self.client_domain.set_peer_authentication(SSLDomain.VERIFY_PEER) ssl1 = _sslConnection(self.client_domain, self.t1, self.c1) ssl2 = _sslConnection(self.server_domain, self.t2, self.c2) _testSaslMech(self, mech, clientUser=None, authUser=None, encrypted=None, authenticated=False) class SASLEventTest(engine.CollectorTest): def setUp(self): engine.CollectorTest.setUp(self) self.t1 = Transport() self.s1 = SASL(self.t1) self.t2 = Transport(Transport.SERVER) self.s2 = SASL(self.t2) self.c1 = Connection() self.c1.user = 'user@proton' self.c1.password = 'password' self.c1.hostname = 'localhost' self.c2 = Connection() self.collector = Collector() def testNormalAuthenticationClient(self): common.ensureCanTestExtendedSASL() self.c1.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5') self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.CONNECTION_REMOTE_OPEN) def testNormalAuthenticationServer(self): common.ensureCanTestExtendedSASL() self.c2.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5') self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.CONNECTION_REMOTE_OPEN) def testFailedAuthenticationClient(self): common.ensureCanTestExtendedSASL() clientUser = "usr@proton" self.c1.user = clientUser self.c1.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5', clientUser=clientUser, authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testFailedAuthenticationServer(self): common.ensureCanTestExtendedSASL() clientUser = "usr@proton" self.c1.user = clientUser self.c2.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5', clientUser=clientUser, authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testNoMechClient(self): common.ensureCanTestExtendedSASL() self.c1.collect(self.collector) self.s2.allowed_mechs('IMPOSSIBLE') self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5', authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testNoMechServer(self): common.ensureCanTestExtendedSASL() self.c2.collect(self.collector) self.s2.allowed_mechs('IMPOSSIBLE') self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'DIGEST-MD5', authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testDisallowedMechClient(self): self.c1.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'IMPOSSIBLE', authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testDisallowedMechServer(self): self.c2.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'IMPOSSIBLE', authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testDisallowedPlainClient(self): self.c1.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'PLAIN', authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_ERROR, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) def testDisallowedPlainServer(self): self.c2.collect(self.collector) self.t1.bind(self.c1) self.t2.bind(self.c2) _testSaslMech(self, 'PLAIN', authenticated=False) self.expect(Event.CONNECTION_INIT, Event.CONNECTION_BOUND, Event.CONNECTION_LOCAL_OPEN, Event.TRANSPORT, Event.TRANSPORT_TAIL_CLOSED, Event.TRANSPORT_ERROR, Event.TRANSPORT_HEAD_CLOSED, Event.TRANSPORT_CLOSED) qpid-proton-0.14.0/tests/python/proton_tests/soak.py0000644000175000017500000003205012770711161022062 0ustar danieldanielfrom __future__ import absolute_import # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os import sys from .common import Test, Skipped, free_tcp_ports, \ MessengerReceiverC, MessengerSenderC, \ MessengerReceiverValgrind, MessengerSenderValgrind, \ MessengerReceiverPython, MessengerSenderPython, \ ReactorReceiverC, ReactorSenderC, \ ReactorReceiverValgrind, ReactorSenderValgrind, \ isSSLPresent from proton import * # # Tests that run the apps # class AppTests(Test): def __init__(self, *args): Test.__init__(self, *args) self.is_valgrind = False def default(self, name, value, **kwargs): if self.is_valgrind: default = kwargs.get("valgrind", value) else: default = value return Test.default(self, name, default, **kwargs) @property def iterations(self): return int(self.default("iterations", 2, fast=1, valgrind=2)) @property def send_count(self): return int(self.default("send_count", 17, fast=1, valgrind=2)) @property def target_count(self): return int(self.default("target_count", 5, fast=1, valgrind=2)) @property def send_batch(self): return int(self.default("send_batch", 7, fast=1, valgrind=2)) @property def forward_count(self): return int(self.default("forward_count", 5, fast=1, valgrind=2)) @property def port_count(self): return int(self.default("port_count", 3, fast=1, valgrind=2)) @property def sender_count(self): return int(self.default("sender_count", 3, fast=1, valgrind=2)) def valgrind_test(self): self.is_valgrind = True def setUp(self): self.senders = [] self.receivers = [] def tearDown(self): pass def _do_test(self, iterations=1): verbose = self.verbose for R in self.receivers: R.start( verbose ) for j in range(iterations): for S in self.senders: S.start( verbose ) for S in self.senders: S.wait() #print("SENDER OUTPUT:") #print( S.stdout() ) assert S.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'" % (str(S.cmdline()), S.status(), S.stdout(), S.stderr())) for R in self.receivers: R.wait() #print("RECEIVER OUTPUT") #print( R.stdout() ) assert R.status() == 0, ("Command '%s' failed status=%d: '%s' '%s'" % (str(R.cmdline()), R.status(), R.stdout(), R.stderr())) # # Traffic passing tests based on the Messenger apps # class MessengerTests(AppTests): _timeout = 60 def _ssl_check(self): if not isSSLPresent(): raise Skipped("No SSL libraries found.") if os.name=="nt": raise Skipped("Windows SChannel lacks anonymous cipher support.") def __init__(self, *args): AppTests.__init__(self, *args) def _do_oneway_test(self, receiver, sender, domain="amqp"): """ Send N messages to a receiver. Parameters: iterations - repeat the senders this many times target_count = # of targets to send to. send_count = # messages sent to each target """ iterations = self.iterations send_count = self.send_count target_count = self.target_count send_total = send_count * target_count receive_total = send_total * iterations port = free_tcp_ports()[0] receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)] receiver.receive_count = receive_total receiver.timeout = MessengerTests._timeout self.receivers.append( receiver ) sender.targets = ["%s://0.0.0.0:%s/X%d" % (domain, port, j) for j in range(target_count)] sender.send_count = send_total sender.timeout = MessengerTests._timeout self.senders.append( sender ) self._do_test(iterations) def _do_echo_test(self, receiver, sender, domain="amqp"): """ Send N messages to a receiver, which responds to each. Parameters: iterations - repeat the senders this many times target_count - # targets to send to send_count = # messages sent to each target send_batch - wait for replies after this many messages sent """ iterations = self.iterations send_count = self.send_count target_count = self.target_count send_batch = self.send_batch send_total = send_count * target_count receive_total = send_total * iterations port = free_tcp_ports()[0] receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)] receiver.receive_count = receive_total receiver.send_reply = True receiver.timeout = MessengerTests._timeout self.receivers.append( receiver ) sender.targets = ["%s://0.0.0.0:%s/%dY" % (domain, port, j) for j in range(target_count)] sender.send_count = send_total sender.get_reply = True sender.send_batch = send_batch sender.timeout = MessengerTests._timeout self.senders.append( sender ) self._do_test(iterations) def _do_relay_test(self, receiver, relay, sender, domain="amqp"): """ Send N messages to a receiver, which replies to each and forwards each of them to different receiver. Parameters: iterations - repeat the senders this many times target_count - # targets to send to send_count = # messages sent to each target send_batch - wait for replies after this many messages sent forward_count - forward to this many targets """ iterations = self.iterations send_count = self.send_count target_count = self.target_count send_batch = self.send_batch forward_count = self.forward_count send_total = send_count * target_count receive_total = send_total * iterations port = free_tcp_ports()[0] receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port)] receiver.receive_count = receive_total receiver.send_reply = True # forward to 'relay' - uses two links # ## THIS FAILS: # receiver.forwards = ["amqp://Relay/%d" % j for j in range(forward_count)] receiver.forwards = ["%s://Relay" % domain] receiver.timeout = MessengerTests._timeout self.receivers.append( receiver ) relay.subscriptions = ["%s://0.0.0.0:%s" % (domain, port)] relay.name = "Relay" relay.receive_count = receive_total relay.timeout = MessengerTests._timeout self.receivers.append( relay ) # send to 'receiver' sender.targets = ["%s://0.0.0.0:%s/X%dY" % (domain, port, j) for j in range(target_count)] sender.send_count = send_total sender.get_reply = True sender.timeout = MessengerTests._timeout self.senders.append( sender ) self._do_test(iterations) def _do_star_topology_test(self, r_factory, s_factory, domain="amqp"): """ A star-like topology, with a central receiver at the hub, and senders at the spokes. Each sender will connect to each of the ports the receiver is listening on. Each sender will then create N links per each connection. Each sender will send X messages per link, waiting for a response. Parameters: iterations - repeat the senders this many times port_count - # of ports the receiver will listen on. Each sender connects to all ports. sender_count - # of senders target_count - # of targets per connection send_count - # of messages sent to each target send_batch - # of messages to send before waiting for response """ iterations = self.iterations port_count = self.port_count sender_count = self.sender_count target_count = self.target_count send_count = self.send_count send_batch = self.send_batch send_total = port_count * target_count * send_count receive_total = send_total * sender_count * iterations ports = free_tcp_ports(port_count) receiver = r_factory() receiver.subscriptions = ["%s://~0.0.0.0:%s" % (domain, port) for port in ports] receiver.receive_count = receive_total receiver.send_reply = True receiver.timeout = MessengerTests._timeout self.receivers.append( receiver ) for i in range(sender_count): sender = s_factory() sender.targets = ["%s://0.0.0.0:%s/%d" % (domain, port, j) for port in ports for j in range(target_count)] sender.send_count = send_total sender.send_batch = send_batch sender.get_reply = True sender.timeout = MessengerTests._timeout self.senders.append( sender ) self._do_test(iterations) def test_oneway_C(self): self._do_oneway_test(MessengerReceiverC(), MessengerSenderC()) def test_oneway_C_SSL(self): self._ssl_check() self._do_oneway_test(MessengerReceiverC(), MessengerSenderC(), "amqps") def test_oneway_valgrind(self): self.valgrind_test() self._do_oneway_test(MessengerReceiverValgrind(), MessengerSenderValgrind()) def test_oneway_Python(self): self._do_oneway_test(MessengerReceiverPython(), MessengerSenderPython()) def test_oneway_C_Python(self): self._do_oneway_test(MessengerReceiverC(), MessengerSenderPython()) def test_oneway_Python_C(self): self._do_oneway_test(MessengerReceiverPython(), MessengerSenderC()) def test_echo_C(self): self._do_echo_test(MessengerReceiverC(), MessengerSenderC()) def test_echo_C_SSL(self): self._ssl_check() self._do_echo_test(MessengerReceiverC(), MessengerSenderC(), "amqps") def test_echo_valgrind(self): self.valgrind_test() self._do_echo_test(MessengerReceiverValgrind(), MessengerSenderValgrind()) def test_echo_Python(self): self._do_echo_test(MessengerReceiverPython(), MessengerSenderPython()) def test_echo_C_Python(self): self._do_echo_test(MessengerReceiverC(), MessengerSenderPython()) def test_echo_Python_C(self): self._do_echo_test(MessengerReceiverPython(), MessengerSenderC()) def test_relay_C(self): self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC()) def test_relay_C_SSL(self): self._ssl_check() self._do_relay_test(MessengerReceiverC(), MessengerReceiverC(), MessengerSenderC(), "amqps") def test_relay_valgrind(self): self.valgrind_test() self._do_relay_test(MessengerReceiverValgrind(), MessengerReceiverValgrind(), MessengerSenderValgrind()) def test_relay_C_Python(self): self._do_relay_test(MessengerReceiverC(), MessengerReceiverPython(), MessengerSenderPython()) def test_relay_Python(self): self._do_relay_test(MessengerReceiverPython(), MessengerReceiverPython(), MessengerSenderPython()) def test_star_topology_C(self): self._do_star_topology_test( MessengerReceiverC, MessengerSenderC ) def test_star_topology_C_SSL(self): self._ssl_check() self._do_star_topology_test( MessengerReceiverC, MessengerSenderC, "amqps" ) def test_star_topology_valgrind(self): self.valgrind_test() self._do_star_topology_test( MessengerReceiverValgrind, MessengerSenderValgrind ) def test_star_topology_Python(self): self._do_star_topology_test( MessengerReceiverPython, MessengerSenderPython ) def test_star_topology_Python_C(self): self._do_star_topology_test( MessengerReceiverPython, MessengerSenderC ) def test_star_topology_C_Python(self): self._do_star_topology_test( MessengerReceiverPython, MessengerSenderC ) def test_oneway_reactor(self): self._do_oneway_test(ReactorReceiverC(), ReactorSenderC()) def test_oneway_reactor_valgrind(self): self.valgrind_test() self._do_oneway_test(ReactorReceiverValgrind(), ReactorSenderValgrind()) qpid-proton-0.14.0/tests/python/proton_tests/ssl.py0000644000175000017500000013665512770711161021746 0ustar danieldanielfrom __future__ import absolute_import # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os from . import common import random import string import subprocess import sys from proton import * from .common import Skipped, pump def _testpath(file): """ Set the full path to the certificate,keyfile, etc. for the test. """ if os.name=="nt": if file.find("private-key")!=-1: # The private key is not in a separate store return None # Substitute pkcs#12 equivalent for the CA/key store if file.endswith(".pem"): file = file[:-4] + ".p12" return os.path.join(os.path.dirname(__file__), "ssl_db/%s" % file) class SslTest(common.Test): def __init__(self, *args): common.Test.__init__(self, *args) self._testpath = _testpath def setUp(self): if not common.isSSLPresent(): raise Skipped("No SSL libraries found.") self.server_domain = SSLDomain(SSLDomain.MODE_SERVER) self.client_domain = SSLDomain(SSLDomain.MODE_CLIENT) def tearDown(self): self.server_domain = None self.client_domain = None class SslTestConnection(object): """ Represents a single SSL connection. """ def __init__(self, domain=None, mode=Transport.CLIENT, session_details=None, conn_hostname=None, ssl_peername=None): if not common.isSSLPresent(): raise Skipped("No SSL libraries found.") self.ssl = None self.domain = domain self.transport = Transport(mode) self.connection = Connection() if conn_hostname: self.connection.hostname = conn_hostname if domain: self.ssl = SSL( self.transport, self.domain, session_details ) if ssl_peername: self.ssl.peer_hostname = ssl_peername # bind last, after all configuration complete: self.transport.bind(self.connection) def _pump(self, ssl_client, ssl_server, buffer_size=1024): pump(ssl_client.transport, ssl_server.transport, buffer_size) def _do_handshake(self, client, server): """ Attempt to connect client to server. Will throw a TransportException if the SSL handshake fails. """ client.connection.open() server.connection.open() self._pump(client, server) if client.transport.closed: return assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump(client, server) def test_defaults(self): if os.name=="nt": raise Skipped("Windows SChannel lacks anonymous cipher support.") """ By default, both the server and the client support anonymous ciphers - they should connect without need for a certificate. """ server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) # check that no SSL connection exists assert not server.ssl.cipher_name() assert not client.ssl.protocol_name() #client.transport.trace(Transport.TRACE_DRV) #server.transport.trace(Transport.TRACE_DRV) client.connection.open() server.connection.open() self._pump( client, server ) # now SSL should be active assert server.ssl.cipher_name() is not None assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_ssl_with_small_buffer(self): self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() small_buffer_size = 1 self._pump( client, server, small_buffer_size ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_server_certificate(self): """ Test that anonymous clients can still connect to a server that has a certificate configured. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_server_authentication(self): """ Simple SSL connection with authentication of the server """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_certificate_fingerprint_and_subfields(self): if os.name=="nt": raise Skipped("Windows support for certificate fingerprint and subfield not implemented yet") if "java" in sys.platform: raise Skipped("Not yet implemented in Proton-J") self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) # give the client a certificate, but let's not require server authentication self.client_domain.set_credentials(self._testpath("client-certificate1.pem"), self._testpath("client-private-key1.pem"), "client-password") self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) # Test the subject subfields self.assertEqual("Client", server.ssl.get_cert_organization()) self.assertEqual("Dev", server.ssl.get_cert_organization_unit()) self.assertEqual("ST", server.ssl.get_cert_state_or_province()) self.assertEqual("US", server.ssl.get_cert_country()) self.assertEqual("City", server.ssl.get_cert_locality_or_city()) self.assertEqual("O=Server,CN=A1.Good.Server.domain.com", client.ssl.get_cert_subject()) self.assertEqual("O=Client,CN=127.0.0.1,C=US,ST=ST,L=City,OU=Dev", server.ssl.get_cert_subject()) self.assertEqual("03c97341abafe5861d6969c66a190d2846d905d6", server.ssl.get_cert_fingerprint_sha1()) self.assertEqual("ad86cc76278e69aef3a5c0dda13fc49831622f92d1364ce1ed361ff842b0143a", server.ssl.get_cert_fingerprint_sha256()) self.assertEqual("9fb3340ecee4471534d60be025358cae33ef2cc9442ca8bb7703a68db68d9ffb7963678292996011fa55a9a2524b84a40a11a2778f25797e78e23cf05623218d", server.ssl.get_cert_fingerprint_sha512()) self.assertEqual("0d4faa84a0bb6846eaec6b7493916b30", server.ssl.get_cert_fingerprint_md5()) # Test the various fingerprint algorithms self.assertEqual("f390ddb4dc8a90bcf3528774b622a7f87f7322b5", client.ssl.get_cert_fingerprint_sha1()) self.assertEqual("c116e902345c99bc01dda14b7a5f1b8ae6a451eddb23e5336c996ba4d12bc122", client.ssl.get_cert_fingerprint_sha256()) self.assertEqual("8941c8ce00824ab7196bb1952787c90ef7f9bd837cbb0bb4823f57fc89e80033c75adc98b78801928d0035bcd6db6ddc9ab6da026c6548a66ede5c4f43f7e166", client.ssl.get_cert_fingerprint_sha512()) self.assertEqual("d008bf05afbc983a3f98ae56e3eba643", client.ssl.get_cert_fingerprint_md5()) self.assertEqual(None, client.ssl.get_cert_fingerprint(21, SSL.SHA1)) # Should be at least 41 self.assertEqual(None, client.ssl.get_cert_fingerprint(50, SSL.SHA256)) # Should be at least 65 self.assertEqual(None, client.ssl.get_cert_fingerprint(128, SSL.SHA512)) # Should be at least 129 self.assertEqual(None, client.ssl.get_cert_fingerprint(10, SSL.MD5)) # Should be at least 33 self.assertEqual(None, client.ssl._get_cert_subject_unknown_subfield()) self.assertNotEqual(None, client.ssl.get_cert_fingerprint(50, SSL.SHA1)) # Should be at least 41 self.assertNotEqual(None, client.ssl.get_cert_fingerprint(70, SSL.SHA256)) # Should be at least 65 self.assertNotEqual(None, client.ssl.get_cert_fingerprint(130, SSL.SHA512)) # Should be at least 129 self.assertNotEqual(None, client.ssl.get_cert_fingerprint(35, SSL.MD5)) # Should be at least 33 self.assertEqual(None, client.ssl._get_cert_fingerprint_unknown_hash_alg()) def test_client_authentication(self): """ Force the client to authenticate. """ # note: when requesting client auth, the server _must_ send its # certificate, so make sure we configure one! self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) # give the client a certificate, but let's not require server authentication self.client_domain.set_credentials(self._testpath("client-certificate.pem"), self._testpath("client-private-key.pem"), "client-password") self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_client_authentication_fail_bad_cert(self): """ Ensure that the server can detect a bad client certificate. """ # note: when requesting client auth, the server _must_ send its # certificate, so make sure we configure one! self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) self.client_domain.set_credentials(self._testpath("bad-server-certificate.pem"), self._testpath("bad-server-private-key.pem"), "server-password") self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT def test_client_authentication_fail_no_cert(self): """ Ensure that the server will fail a client that does not provide a certificate. """ # note: when requesting client auth, the server _must_ send its # certificate, so make sure we configure one! self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT def test_client_server_authentication(self): """ Require both client and server to mutually identify themselves. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) self.client_domain.set_credentials(self._testpath("client-certificate.pem"), self._testpath("client-private-key.pem"), "client-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_server_only_authentication(self): """ Client verifies server, but server does not verify client. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) self.client_domain.set_credentials(self._testpath("client-certificate.pem"), self._testpath("client-private-key.pem"), "client-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_bad_server_certificate(self): """ A server with a self-signed certificate that is not trusted by the client. The client should reject the server. """ self.server_domain.set_credentials(self._testpath("bad-server-certificate.pem"), self._testpath("bad-server-private-key.pem"), "server-password") self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT del server del client # now re-try with a client that does not require peer verification self.client_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) client = SslTest.SslTestConnection( self.client_domain ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_allow_unsecured_client_which_connects_unsecured(self): """ Server allows an unsecured client to connect if configured. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) # allow unsecured clients on this connection self.server_domain.allow_unsecured_client() server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) # non-ssl connection client = SslTest.SslTestConnection() client.connection.open() server.connection.open() self._pump( client, server ) assert server.ssl.protocol_name() is None client.connection.close() server.connection.close() self._pump( client, server ) def test_allow_unsecured_client_which_connects_secured(self): """ As per test_allow_unsecured_client_which_connects_unsecured but client actually uses SSL """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) self.client_domain.set_credentials(self._testpath("client-certificate.pem"), self._testpath("client-private-key.pem"), "client-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) # allow unsecured clients on this connection #self.server_domain.allow_unsecured_client() # client uses ssl. Server should detect this. client = SslTest.SslTestConnection( self.client_domain ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client.connection.open() server.connection.open() self._pump( client, server ) assert server.ssl.protocol_name() is not None client.connection.close() server.connection.close() self._pump( client, server ) def test_disallow_unsecured_client(self): """ Non-SSL Client is disallowed from connecting to server. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) # non-ssl connection client = SslTest.SslTestConnection() client.connection.open() server.connection.open() self._pump( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT def test_session_resume(self): """ Test resume of client session. """ if os.name=="nt": raise Skipped("Windows SChannel session resume not yet implemented.") self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_peer_authentication( SSLDomain.ANONYMOUS_PEER ) self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) # details will be used in initial and subsequent connections to allow session to be resumed initial_session_details = SSLSessionDetails("my-session-id") server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain, session_details=initial_session_details ) # bring up the connection and store its state client.connection.open() server.connection.open() self._pump( client, server ) assert client.ssl.protocol_name() is not None # cleanly shutdown the connection client.connection.close() server.connection.close() self._pump( client, server ) # destroy the existing clients del client del server # now create a new set of connections, use last session id server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) # provide the details of the last session, allowing it to be resumed client = SslTest.SslTestConnection( self.client_domain, session_details=initial_session_details ) #client.transport.trace(Transport.TRACE_DRV) #server.transport.trace(Transport.TRACE_DRV) client.connection.open() server.connection.open() self._pump( client, server ) assert server.ssl.protocol_name() is not None if(API_LANGUAGE=="C"): assert client.ssl.resume_status() == SSL.RESUME_REUSED else: # Java gives no way to check whether a previous session has been resumed pass client.connection.close() server.connection.close() self._pump( client, server ) # now try to resume using an unknown session-id, expect resume to fail # and a new session is negotiated del client del server server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain, session_details=SSLSessionDetails("some-other-session-id") ) client.connection.open() server.connection.open() self._pump( client, server ) assert server.ssl.protocol_name() is not None if(API_LANGUAGE=="C"): assert client.ssl.resume_status() == SSL.RESUME_NEW client.connection.close() server.connection.close() self._pump( client, server ) def test_multiple_sessions(self): """ Test multiple simultaineous active SSL sessions with bi-directional certificate verification, shared across two domains. """ self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.server_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.server_domain.set_peer_authentication( SSLDomain.VERIFY_PEER, self._testpath("ca-certificate.pem") ) self.client_domain.set_credentials(self._testpath("client-certificate.pem"), self._testpath("client-private-key.pem"), "client-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) max_count = 100 sessions = [(SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ), SslTest.SslTestConnection( self.client_domain )) for x in range(max_count)] for s in sessions: s[0].connection.open() self._pump( s[0], s[1] ) for s in sessions: s[1].connection.open() self._pump( s[1], s[0] ) assert s[0].ssl.cipher_name() is not None assert s[1].ssl.cipher_name() == s[0].ssl.cipher_name() for s in sessions: s[1].connection.close() self._pump( s[0], s[1] ) for s in sessions: s[0].connection.close() self._pump( s[1], s[0] ) def test_server_hostname_authentication(self): """ Test authentication of the names held in the server's certificate against various configured hostnames. """ if os.name=="nt": raise Skipped("PROTON-1057: disable temporarily on Windows.") # Check the CommonName matches (case insensitive). # Assumes certificate contains "CN=A1.Good.Server.domain.com" self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "a1.good.server.domain.com" assert client.ssl.peer_hostname == "a1.good.server.domain.com" self._do_handshake( client, server ) del server del client self.tearDown() # Should fail on CN name mismatch: self.setUp() self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "A1.Good.Server.domain.comX" self._do_handshake( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT del server del client self.tearDown() # Wildcarded Certificate # Assumes: # 1) certificate contains Server Alternate Names: # "alternate.name.one.com" and "another.name.com" # 2) certificate has wildcarded CommonName "*.prefix*.domain.com" # # Pass: match an alternate self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "alternate.Name.one.com" self._do_handshake( client, server ) del client del server self.tearDown() # Pass: match an alternate self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "ANOTHER.NAME.COM" self._do_handshake(client, server) del client del server self.tearDown() # Pass: match the pattern self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "SOME.PREfix.domain.COM" self._do_handshake( client, server ) del client del server self.tearDown() # Pass: match the pattern self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "FOO.PREfixZZZ.domain.com" self._do_handshake( client, server ) del client del server self.tearDown() # Fail: must match prefix on wildcard self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "FOO.PREfi.domain.com" self._do_handshake( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT del server del client self.tearDown() # Fail: leading wildcards are not optional self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) client.ssl.peer_hostname = "PREfix.domain.COM" self._do_handshake( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT self.tearDown() # Pass: ensure that the user can give an alternate name that overrides # the connection's configured hostname self.setUp() self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER) client = SslTest.SslTestConnection(self.client_domain, conn_hostname="This.Name.Does.not.Match", ssl_peername="alternate.name.one.com") self._do_handshake(client, server) del client del server self.tearDown() # Pass: ensure that the hostname supplied by the connection is used if # none has been specified for the SSL instanace self.setUp() self.server_domain.set_credentials(self._testpath("server-certificate.pem"), self._testpath("server-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection(self.server_domain, mode=Transport.SERVER) client = SslTest.SslTestConnection(self.client_domain, conn_hostname="a1.good.server.domain.com") self._do_handshake(client, server) del client del server self.tearDown() def test_server_hostname_authentication_2(self): """Initially separated from test_server_hostname_authentication above to force Windows checking and sidestep PROTON-1057 exclusion. """ # Fail for a null peer name. self.server_domain.set_credentials(self._testpath("server-wc-certificate.pem"), self._testpath("server-wc-private-key.pem"), "server-password") self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER_NAME ) server = SslTest.SslTestConnection( self.server_domain, mode=Transport.SERVER ) client = SslTest.SslTestConnection( self.client_domain ) # Next line results in an eventual pn_ssl_set_peer_hostname(client.ssl._ssl, None) client.ssl.peer_hostname = None self._do_handshake( client, server ) assert client.transport.closed assert server.transport.closed assert client.connection.state & Endpoint.REMOTE_UNINIT assert server.connection.state & Endpoint.REMOTE_UNINIT self.tearDown() def test_defaults_messenger_app(self): """ Test an SSL connection using the Messenger apps (no certificates) """ if os.name=="nt": raise Skipped("Windows SChannel lacks anonymous cipher support.") port = common.free_tcp_ports()[0] receiver = common.MessengerReceiverC() receiver.subscriptions = ["amqps://~0.0.0.0:%s" % port] receiver.receive_count = 1 receiver.timeout = self.timeout receiver.start() sender = common.MessengerSenderC() sender.targets = ["amqps://0.0.0.0:%s/X" % port] sender.send_count = 1 sender.timeout = self.timeout sender.start() sender.wait() assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline()) receiver.wait() assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline()) def test_server_authentication_messenger_app(self): """ Test an SSL authentication using the Messenger apps. """ port = common.free_tcp_ports()[0] receiver = common.MessengerReceiverC() receiver.subscriptions = ["amqps://~0.0.0.0:%s" % port] receiver.receive_count = 1 receiver.timeout = self.timeout # Note hack - by default we use the client-certificate for the # _server_ because the client-certificate's common name field # is "127.0.0.1", which will match the target address used by # the sender. receiver.certificate = self._testpath("client-certificate.pem") receiver.privatekey = self._testpath("client-private-key.pem") receiver.password = "client-password" receiver.start() sender = common.MessengerSenderC() sender.targets = ["amqps://127.0.0.1:%s/X" % port] sender.send_count = 1 sender.timeout = self.timeout sender.ca_db = self._testpath("ca-certificate.pem") sender.start() sender.wait() assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline()) receiver.wait() assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline()) def DISABLED_test_defaults_valgrind(self): """ Run valgrind over a simple SSL connection (no certificates) """ # the openssl libraries produce far too many valgrind errors to be # useful. AFAIK, there is no way to wriate a valgrind suppression # expression that will ignore all errors from a given library. # Until we can, skip this test. port = common.free_tcp_ports()[0] receiver = common.MessengerReceiverValgrind() receiver.subscriptions = ["amqps://~127.0.0.1:%s" % port] receiver.receive_count = 1 receiver.timeout = self.timeout receiver.start() sender = common.MessengerSenderValgrind() sender.targets = ["amqps://127.0.0.1:%s/X" % port] sender.send_count = 1 sender.timeout = self.timeout sender.start() sender.wait() assert sender.status() == 0, "Command '%s' failed" % str(sender.cmdline()) receiver.wait() assert receiver.status() == 0, "Command '%s' failed" % str(receiver.cmdline()) # self.server_domain.set_credentials(self._testpath("client-certificate.pem"), # self._testpath("client-private-key.pem"), # "client-password") # self.client_domain.set_trusted_ca_db(self._testpath("ca-certificate.pem")) # self.client_domain.set_peer_authentication( SSLDomain.VERIFY_PEER ) def test_singleton(self): """Verify that only a single instance of SSL can exist per Transport""" transport = Transport() ssl1 = SSL(transport, self.client_domain) ssl2 = transport.ssl(self.client_domain) ssl3 = transport.ssl(self.client_domain) assert ssl1 is ssl2 assert ssl1 is ssl3 transport = Transport() ssl1 = transport.ssl(self.client_domain) ssl2 = SSL(transport, self.client_domain) assert ssl1 is ssl2 # catch attempt to re-configure existing SSL try: ssl3 = SSL(transport, self.server_domain) assert False, "Expected error did not occur!" except SSLException: pass class MessengerSSLTests(common.Test): def setUp(self): if not common.isSSLPresent(): raise Skipped("No SSL libraries found.") self.server = Messenger() self.client = Messenger() self.server.blocking = False self.client.blocking = False def tearDown(self): self.server.stop() self.client.stop() self.pump() assert self.server.stopped assert self.client.stopped def pump(self, timeout=0): while self.client.work(0) or self.server.work(0): pass self.client.work(timeout) self.server.work(timeout) while self.client.work(0) or self.server.work(0): pass def test_server_credentials(self, cert="server-certificate.pem", key="server-private-key.pem", password="server-password", exception=None): import sys # java doesn't do validation in the same way (yet) if exception and "java" in sys.platform: raise Skipped() self.server.certificate = _testpath(cert) self.server.private_key = _testpath(key) self.server.password = password port = common.free_tcp_ports()[0] try: self.server.start() self.server.subscribe("amqps://~0.0.0.0:%s" % port) if exception is not None: assert False, "expected failure did not occur" except MessengerException: e = sys.exc_info()[1] if exception: assert exception in str(e), str(e) else: raise e def test_server_credentials_bad_cert(self): self.test_server_credentials(cert="bad", exception="invalid credentials") def test_server_credentials_bad_key(self): self.test_server_credentials(key="bad", exception="invalid credentials") def test_server_credentials_bad_password(self): self.test_server_credentials(password="bad", exception="invalid credentials") def test_client_credentials(self, trusted="ca-certificate.pem", cert="client-certificate.pem", key="client-private-key.pem", password="client-password", altserv=False, fail=False): if altserv: self.server.certificate = _testpath("bad-server-certificate.pem") self.server.private_key = _testpath("bad-server-private-key.pem") self.server.password = "server-password" else: self.server.certificate = _testpath("client-certificate.pem") self.server.private_key = _testpath("client-private-key.pem") self.server.password = "client-password" self.server.start() port = common.free_tcp_ports()[0] self.server.subscribe("amqps://~0.0.0.0:%s" % port) self.server.incoming_window = 10 self.client.trusted_certificates = _testpath(trusted) self.client.certificate = _testpath(cert) self.client.private_key = _testpath(key) self.client.password = password self.client.outgoing_window = 10 self.client.start() self.server.recv() msg = Message() msg.address = "amqps://127.0.0.1:%s" % port # make sure a large, uncompressible message body works! msg.body = "".join(random.choice(string.ascii_letters) for x in range(10099)) trk = self.client.put(msg) self.client.send() self.pump() if fail: assert self.server.incoming == 0, self.server.incoming assert self.client.status(trk) == ABORTED, self.client.status(trk) else: assert self.server.incoming == 1, self.server.incoming rmsg = Message() self.server.get(rmsg) assert rmsg.body == msg.body self.server.accept() self.pump() assert self.client.status(trk) == ACCEPTED, self.client.status(trk) def test_client_credentials_bad_cert(self): self.test_client_credentials(cert="bad", fail=True) def test_client_credentials_bad_trusted(self): self.test_client_credentials(trusted="bad", fail=True) def test_client_credentials_bad_password(self): self.test_client_credentials(password="bad", fail=True) def test_client_credentials_untrusted(self): self.test_client_credentials(altserv=True, fail=True) qpid-proton-0.14.0/tests/python/proton_tests/transport.py0000644000175000017500000002570712770711161023174 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os import sys from . import common from proton import * from proton._compat import str2bin class Test(common.Test): pass class ClientTransportTest(Test): def setUp(self): self.transport = Transport() self.peer = Transport() self.conn = Connection() self.peer.bind(self.conn) def tearDown(self): self.transport = None self.peer = None self.conn = None def drain(self): while True: p = self.transport.pending() if p < 0: return elif p > 0: data = self.transport.peek(p) self.peer.push(data) self.transport.pop(len(data)) else: assert False def assert_error(self, name): assert self.conn.remote_container is None, self.conn.remote_container self.drain() # verify that we received an open frame assert self.conn.remote_container is not None, self.conn.remote_container # verify that we received a close frame assert self.conn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_CLOSED, self.conn.state # verify that a framing error was reported assert self.conn.remote_condition.name == name, self.conn.remote_condition def testEOS(self): self.transport.push(str2bin("")) # should be a noop self.transport.close_tail() # should result in framing error self.assert_error(u'amqp:connection:framing-error') def testPartial(self): self.transport.push(str2bin("AMQ")) # partial header self.transport.close_tail() # should result in framing error self.assert_error(u'amqp:connection:framing-error') def testGarbage(self, garbage=str2bin("GARBAGE_")): self.transport.push(garbage) self.assert_error(u'amqp:connection:framing-error') assert self.transport.pending() < 0 self.transport.close_tail() assert self.transport.pending() < 0 def testSmallGarbage(self): self.testGarbage(str2bin("XXX")) def testBigGarbage(self): self.testGarbage(str2bin("GARBAGE_XXX")) def testHeader(self): self.transport.push(str2bin("AMQP\x00\x01\x00\x00")) self.transport.close_tail() self.assert_error(u'amqp:connection:framing-error') def testHeaderBadDOFF1(self): """Verify doff > size error""" self.testGarbage(str2bin("AMQP\x00\x01\x00\x00\x00\x00\x00\x08\x08\x00\x00\x00")) def testHeaderBadDOFF2(self): """Verify doff < 2 error""" self.testGarbage(str2bin("AMQP\x00\x01\x00\x00\x00\x00\x00\x08\x01\x00\x00\x00")) def testHeaderBadSize(self): """Verify size > max_frame_size error""" self.transport.max_frame_size = 512 self.testGarbage(str2bin("AMQP\x00\x01\x00\x00\x00\x00\x02\x01\x02\x00\x00\x00")) def testProtocolNotSupported(self): self.transport.push(str2bin("AMQP\x01\x01\x0a\x00")) p = self.transport.pending() assert p >= 8, p bytes = self.transport.peek(p) assert bytes[:8] == str2bin("AMQP\x00\x01\x00\x00") self.transport.pop(p) self.drain() assert self.transport.closed def testPeek(self): out = self.transport.peek(1024) assert out is not None def testBindAfterOpen(self): conn = Connection() ssn = conn.session() conn.open() ssn.open() conn.container = "test-container" conn.hostname = "test-hostname" trn = Transport() trn.bind(conn) out = trn.peek(1024) assert str2bin("test-container") in out, repr(out) assert str2bin("test-hostname") in out, repr(out) self.transport.push(out) c = Connection() assert c.remote_container == None assert c.remote_hostname == None assert c.session_head(0) == None self.transport.bind(c) assert c.remote_container == "test-container" assert c.remote_hostname == "test-hostname" assert c.session_head(0) != None def testCloseHead(self): n = self.transport.pending() assert n > 0, n try: self.transport.close_head() except TransportException: e = sys.exc_info()[1] assert "aborted" in str(e), str(e) n = self.transport.pending() assert n < 0, n def testCloseTail(self): n = self.transport.capacity() assert n > 0, n try: self.transport.close_tail() except TransportException: e = sys.exc_info()[1] assert "aborted" in str(e), str(e) n = self.transport.capacity() assert n < 0, n def testUnpairedPop(self): conn = Connection() self.transport.bind(conn) conn.hostname = "hostname" conn.open() dat1 = self.transport.peek(1024) ssn = conn.session() ssn.open() dat2 = self.transport.peek(1024) assert dat2[:len(dat1)] == dat1 snd = ssn.sender("sender") snd.open() self.transport.pop(len(dat1)) self.transport.pop(len(dat2) - len(dat1)) dat3 = self.transport.peek(1024) self.transport.pop(len(dat3)) assert self.transport.peek(1024) == str2bin("") self.peer.push(dat1) self.peer.push(dat2[len(dat1):]) self.peer.push(dat3) class ServerTransportTest(Test): def setUp(self): self.transport = Transport(Transport.SERVER) self.peer = Transport() self.conn = Connection() self.peer.bind(self.conn) def tearDOwn(self): self.transport = None self.peer = None self.conn = None def drain(self): while True: p = self.transport.pending() if p < 0: return elif p > 0: bytes = self.transport.peek(p) self.peer.push(bytes) self.transport.pop(len(bytes)) else: assert False def assert_error(self, name): assert self.conn.remote_container is None, self.conn.remote_container self.drain() # verify that we received an open frame assert self.conn.remote_container is not None, self.conn.remote_container # verify that we received a close frame assert self.conn.state == Endpoint.LOCAL_UNINIT | Endpoint.REMOTE_CLOSED, self.conn.state # verify that a framing error was reported assert self.conn.remote_condition.name == name, self.conn.remote_condition # TODO: This may no longer be testing anything def testEOS(self): self.transport.push(str2bin("")) # should be a noop self.transport.close_tail() p = self.transport.pending() self.drain() assert self.transport.closed def testPartial(self): self.transport.push(str2bin("AMQ")) # partial header self.transport.close_tail() p = self.transport.pending() assert p >= 8, p bytes = self.transport.peek(p) assert bytes[:8] == str2bin("AMQP\x00\x01\x00\x00") self.transport.pop(p) self.drain() assert self.transport.closed def testGarbage(self, garbage="GARBAGE_"): self.transport.push(str2bin(garbage)) p = self.transport.pending() assert p >= 8, p bytes = self.transport.peek(p) assert bytes[:8] == str2bin("AMQP\x00\x01\x00\x00") self.transport.pop(p) self.drain() assert self.transport.closed def testSmallGarbage(self): self.testGarbage("XXX") def testBigGarbage(self): self.testGarbage("GARBAGE_XXX") def testHeader(self): self.transport.push(str2bin("AMQP\x00\x01\x00\x00")) self.transport.close_tail() self.assert_error(u'amqp:connection:framing-error') def testProtocolNotSupported(self): self.transport.push(str2bin("AMQP\x01\x01\x0a\x00")) p = self.transport.pending() assert p >= 8, p bytes = self.transport.peek(p) assert bytes[:8] == str2bin("AMQP\x00\x01\x00\x00") self.transport.pop(p) self.drain() assert self.transport.closed def testPeek(self): out = self.transport.peek(1024) assert out is not None def testBindAfterOpen(self): conn = Connection() ssn = conn.session() conn.open() ssn.open() conn.container = "test-container" conn.hostname = "test-hostname" trn = Transport() trn.bind(conn) out = trn.peek(1024) assert str2bin("test-container") in out, repr(out) assert str2bin("test-hostname") in out, repr(out) self.transport.push(out) c = Connection() assert c.remote_container == None assert c.remote_hostname == None assert c.session_head(0) == None self.transport.bind(c) assert c.remote_container == "test-container" assert c.remote_hostname == "test-hostname" assert c.session_head(0) != None def testCloseHead(self): n = self.transport.pending() assert n >= 0, n try: self.transport.close_head() except TransportException: e = sys.exc_info()[1] assert "aborted" in str(e), str(e) n = self.transport.pending() assert n < 0, n def testCloseTail(self): n = self.transport.capacity() assert n > 0, n try: self.transport.close_tail() except TransportException: e = sys.exc_info()[1] assert "aborted" in str(e), str(e) n = self.transport.capacity() assert n < 0, n def testUnpairedPop(self): conn = Connection() self.transport.bind(conn) conn.hostname = "hostname" conn.open() dat1 = self.transport.peek(1024) ssn = conn.session() ssn.open() dat2 = self.transport.peek(1024) assert dat2[:len(dat1)] == dat1 snd = ssn.sender("sender") snd.open() self.transport.pop(len(dat1)) self.transport.pop(len(dat2) - len(dat1)) dat3 = self.transport.peek(1024) self.transport.pop(len(dat3)) assert self.transport.peek(1024) == str2bin("") self.peer.push(dat1) self.peer.push(dat2[len(dat1):]) self.peer.push(dat3) def testEOSAfterSASL(self): self.transport.sasl().allowed_mechs('ANONYMOUS') self.peer.sasl().allowed_mechs('ANONYMOUS') # this should send over the sasl header plus a sasl-init set up # for anonymous p = self.peer.pending() self.transport.push(self.peer.peek(p)) self.peer.pop(p) # now we send EOS self.transport.close_tail() # the server may send an error back p = self.transport.pending() while p>0: self.peer.push(self.transport.peek(p)) self.transport.pop(p) p = self.transport.pending() # server closed assert self.transport.pending() < 0 class LogTest(Test): def testTracer(self): t = Transport() assert t.tracer is None messages = [] def tracer(transport, message): messages.append((transport, message)) t.tracer = tracer assert t.tracer is tracer t.log("one") t.log("two") t.log("three") assert messages == [(t, "one"), (t, "two"), (t, "three")], messages qpid-proton-0.14.0/tests/python/proton_tests/utils.py0000644000175000017500000001621312770711161022270 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # import os, time, sys from threading import Thread, Event from unittest import TestCase from proton_tests.common import Test, free_tcp_port from copy import copy from proton import Message, Url, generate_uuid, Array, UNDESCRIBED, Data, symbol, ConnectionException from proton.handlers import MessagingHandler from proton.reactor import Container from proton.utils import SyncRequestResponse, BlockingConnection from .common import Skipped, ensureCanTestExtendedSASL CONNECTION_PROPERTIES={u'connection': u'properties'} OFFERED_CAPABILITIES = Array(UNDESCRIBED, Data.SYMBOL, symbol("O_one"), symbol("O_two"), symbol("O_three")) DESIRED_CAPABILITIES = Array(UNDESCRIBED, Data.SYMBOL, symbol("D_one"), symbol("D_two"), symbol("D_three")) ANONYMOUS='ANONYMOUS' EXTERNAL='EXTERNAL' class EchoServer(MessagingHandler, Thread): """ Simple echo server that echos messages to their reply-to. Runs in a thread. Will only accept a single connection and shut down when that connection closes. """ def __init__(self, url, timeout): MessagingHandler.__init__(self) Thread.__init__(self) self.daemon = True self.timeout = timeout self.url = url self.senders = {} self.container = None self.event = Event() def on_start(self, event): self.acceptor = event.container.listen(self.url) self.container = event.container self.event.set() def on_link_opening(self, event): if event.link.is_sender: if event.link.remote_source and event.link.remote_source.dynamic: event.link.source.address = str(generate_uuid()) self.senders[event.link.source.address] = event.link def on_message(self, event): m = event.message sender = self.senders.get(m.reply_to) if sender: reply = Message(address=m.reply_to, body=m.body, correlation_id=m.correlation_id) sender.send(reply) def on_connection_closing(self, event): self.acceptor.close() def run(self): Container(self).run() def wait(self): self.event.wait(self.timeout) class ConnPropertiesServer(EchoServer): def __init__(self, url, timeout): EchoServer.__init__(self, url, timeout) self.properties_received = False self.offered_capabilities_received = False self.desired_capabilities_received = False def on_connection_opening(self, event): conn = event.connection if conn.remote_properties == CONNECTION_PROPERTIES: self.properties_received = True if conn.remote_offered_capabilities == OFFERED_CAPABILITIES: self.offered_capabilities_received = True if conn.remote_desired_capabilities == DESIRED_CAPABILITIES: self.desired_capabilities_received = True class SyncRequestResponseTest(Test): """Test SyncRequestResponse""" def test_request_response(self): ensureCanTestExtendedSASL() def test(name, address="x"): for i in range(5): body="%s%s" % (name, i) response = client.call(Message(address=address, body=body)) self.assertEquals(response.address, client.reply_to) self.assertEquals(response.body, body) server = EchoServer(Url(host="127.0.0.1", port=free_tcp_port()), self.timeout) server.start() server.wait() connection = BlockingConnection(server.url, timeout=self.timeout) client = SyncRequestResponse(connection) try: test("foo") # Simple request/resposne finally: client.connection.close() server.join(timeout=self.timeout) def test_connection_properties(self): ensureCanTestExtendedSASL() server = ConnPropertiesServer(Url(host="127.0.0.1", port=free_tcp_port()), timeout=self.timeout) server.start() server.wait() connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES) client = SyncRequestResponse(connection) client.connection.close() server.join(timeout=self.timeout) self.assertEquals(server.properties_received, True) self.assertEquals(server.offered_capabilities_received, True) self.assertEquals(server.desired_capabilities_received, True) def test_allowed_mechs_external(self): # All this test does it make sure that if we pass allowed_mechs to BlockingConnection, it is actually used. if "java" in sys.platform: raise Skipped("") port = free_tcp_port() server = ConnPropertiesServer(Url(host="127.0.0.1", port=port), timeout=self.timeout) server.start() server.wait() try: # This will cause an exception because we are specifying allowed_mechs as EXTERNAL. The SASL handshake will fail because the server is not setup to handle EXTERNAL connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES, allowed_mechs=EXTERNAL) self.fail("Expected ConnectionException") except ConnectionException as e: self.assertTrue('amqp:unauthorized-access' in str(e), "expected unauthorized-access") server.join(timeout=self.timeout) def test_allowed_mechs_anonymous(self): # All this test does it make sure that if we pass allowed_mechs to BlockingConnection, it is actually used. server = ConnPropertiesServer(Url(host="127.0.0.1", port=free_tcp_port()), timeout=self.timeout) server.start() server.wait() # An ANONYMOUS allowed_mechs will work, anonymous connections are allowed by ConnPropertiesServer connection = BlockingConnection(server.url, timeout=self.timeout, properties=CONNECTION_PROPERTIES, offered_capabilities=OFFERED_CAPABILITIES, desired_capabilities=DESIRED_CAPABILITIES, allowed_mechs=ANONYMOUS) client = SyncRequestResponse(connection) client.connection.close() server.join(timeout=self.timeout) self.assertEquals(server.properties_received, True) self.assertEquals(server.offered_capabilities_received, True) self.assertEquals(server.desired_capabilities_received, True) qpid-proton-0.14.0/tests/python/proton_tests/valgrind.supp0000644000175000017500000000413712770711161023277 0ustar danieldaniel{ SSL does a number of uninitialized accesses (expected) 1 Memcheck:Cond fun:BN_bin2bn obj:* obj:* } { SSL does a number of uninitialized accesses (expected) 2 Memcheck:Cond fun:BN_num_bits_word fun:BN_num_bits } { SSL does a number of uninitialized accesses (expected) 3 Memcheck:Value8 fun:BN_num_bits_word fun:BN_num_bits fun:BN_mod_exp_mont_consttime obj:* fun:ssl3_ctx_ctrl } { SSL does a number of uninitialized accesses (expected) 4 Memcheck:Value8 fun:BN_mod_exp_mont_consttime obj:* fun:ssl3_ctx_ctrl } { SSL does a number of uninitialized accesses (FreeBSD version) Memcheck:Value8 fun:BN_num_bits_word fun:BN_num_bits fun:BN_mod_exp_mont_consttime fun:BN_mod_exp_mont obj:*libcrypto.so* fun:ssl3_ctx_ctrl } { SSL does a number of uninitialized accesses (FreeBSD version) Memcheck:Value8 fun:BN_mod_exp_mont_consttime fun:BN_mod_exp_mont obj:*libcrypto.so* fun:ssl3_ctx_ctrl } { SSL does a number of uninitialized accesses (expected) 5 Memcheck:Value4 fun:BN_mod_exp_mont_consttime fun:BN_mod_exp_mont obj:* obj:* } { SSL does a number of uninitialized accesses (expected) 6 Memcheck:Value4 fun:BN_num_bits_word fun:BN_mod_exp_mont_consttime fun:BN_mod_exp_mont obj:* obj:* } { Since we can never safely uninitialize SSL, allow this Memcheck:Leak fun:_vgrZU_libcZdsoZa_realloc fun:CRYPTO_realloc fun:lh_insert obj:/lib64/libcrypto.so.0.9.8e fun:ERR_load_strings fun:ERR_load_X509V3_strings fun:ERR_load_crypto_strings fun:SSL_load_error_strings } { Since we can never safely uninitialize SSL, allow this Memcheck:Leak fun:_vgrZU_libcZdsoZa_malloc fun:CRYPTO_malloc fun:lh_new fun:OBJ_NAME_init fun:OBJ_NAME_add fun:EVP_add_cipher fun:SSL_library_init } { Since we can never safely uninitialize SSL, allow this Memcheck:Leak fun:malloc obj:* fun:CRYPTO_malloc } { Known memory leak in cyrus-sasl (fixed in 2.1.26) Memcheck:Leak fun:malloc fun:* fun:sasl_config_init fun:sasl_server_init } qpid-proton-0.14.0/tests/python/proton-test0000755000175000017500000004657312770711161020253 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # TODO: summarize, test harness preconditions (e.g. broker is alive) import logging, optparse, os, struct, sys, time, traceback, types, cgi from fnmatch import fnmatchcase as match from getopt import GetoptError from logging import getLogger, StreamHandler, Formatter, Filter, \ WARN, DEBUG, ERROR import unittest from proton_tests.common import SkipTest if sys.version_info[0] == 3: CLASS_TYPES = (type,) else: CLASS_TYPES = (type, types.ClassType) levels = { "DEBUG": DEBUG, "WARN": WARN, "ERROR": ERROR } sorted_levels = [(v, k) for k, v in list(levels.items())] sorted_levels.sort() sorted_levels = [v for k, v in sorted_levels] parser = optparse.OptionParser(usage="usage: %prog [options] PATTERN ...", description="Run tests matching the specified PATTERNs.") parser.add_option("-l", "--list", action="store_true", default=False, help="list tests instead of executing them") parser.add_option("-f", "--log-file", metavar="FILE", help="log output to FILE") parser.add_option("-v", "--log-level", metavar="LEVEL", default="WARN", help="only display log messages of LEVEL or higher severity: " "%s (default %%default)" % ", ".join(sorted_levels)) parser.add_option("-c", "--log-category", metavar="CATEGORY", action="append", dest="log_categories", default=[], help="log only categories matching CATEGORY pattern") parser.add_option("-m", "--module", action="append", default=[], dest="modules", help="add module to test search path") parser.add_option("-i", "--ignore", action="append", default=[], help="ignore tests matching IGNORE pattern") parser.add_option("-I", "--ignore-file", metavar="IFILE", action="append", default=[], help="ignore tests matching patterns in IFILE") parser.add_option("-H", "--halt-on-error", action="store_true", default=False, dest="hoe", help="halt if an error is encountered") parser.add_option("-t", "--time", action="store_true", default=False, help="report timing information on test run") parser.add_option("-D", "--define", metavar="DEFINE", dest="defines", action="append", default=[], help="define test parameters") parser.add_option("-x", "--xml", metavar="XML", dest="xml", help="write test results in Junit style xml suitable for use by CI tools etc") parser.add_option("-a", "--always-colorize", action="store_true", dest="always_colorize", default=False, help="always colorize the test results rather than relying on terminal tty detection. Useful when invoked from Jython/Maven.") parser.add_option("-n", metavar="count", dest="count", type=int, default=1, help="run the tests times") parser.add_option("-b", "--bare", action="store_true", default=False, help="Run bare, i.e. don't capture stack traces. This is useful under Jython as " + "captured stack traces do not include the Java portion of the stack," + "whereas non captured stack traces do.") parser.add_option("-j", "--javatrace", action="store_true", default=False, help="Show the full java stack trace. This disables heuristics to eliminate the " + "jython portion of java stack traces.") class Config: def __init__(self): self.defines = {} self.log_file = None self.log_level = WARN self.log_categories = [] opts, args = parser.parse_args() includes = [] excludes = ["*__*__"] config = Config() list_only = opts.list for d in opts.defines: try: idx = d.index("=") name = d[:idx] value = d[idx+1:] config.defines[name] = value except ValueError: config.defines[d] = None config.log_file = opts.log_file config.log_level = levels[opts.log_level.upper()] config.log_categories = opts.log_categories excludes.extend([v.strip() for v in opts.ignore]) for v in opts.ignore_file: f = open(v) for line in f: line = line.strip() if line.startswith("#"): continue excludes.append(line) f.close() for a in args: includes.append(a.strip()) if not includes: includes.append("*") def is_ignored(path): for p in excludes: if match(path, p): return True return False def is_included(path): if is_ignored(path): return False for p in includes: if match(path, p): return True return False def is_smart(): return sys.stdout.isatty() and os.environ.get("TERM", "dumb") != "dumb" try: import fcntl, termios def width(): if is_smart(): s = struct.pack("HHHH", 0, 0, 0, 0) fd_stdout = sys.stdout.fileno() x = fcntl.ioctl(fd_stdout, termios.TIOCGWINSZ, s) rows, cols, xpx, ypx = struct.unpack("HHHH", x) return cols else: try: return int(os.environ.get("COLUMNS", "80")) except ValueError: return 80 WIDTH = width() def resize(sig, frm): global WIDTH WIDTH = width() import signal signal.signal(signal.SIGWINCH, resize) except ImportError: WIDTH = 80 def vt100_attrs(*attrs): return "\x1B[%sm" % ";".join(map(str, attrs)) vt100_reset = vt100_attrs(0) KEYWORDS = {"pass": (32,), "skip": (33,), "fail": (31,), "start": (34,), "total": (34,), "ignored": (33,), "selected": (34,), "elapsed": (34,), "average": (34,)} def colorize_word(word, text=None): if text is None: text = word return colorize(text, *KEYWORDS.get(word, ())) def colorize(text, *attrs): if attrs and (is_smart() or opts.always_colorize): return "%s%s%s" % (vt100_attrs(*attrs), text, vt100_reset) else: return text def indent(text): lines = text.split("\n") return " %s" % "\n ".join(lines) # Write a 'minimal' Junit xml style report file suitable for use by CI tools such as Jenkins. class JunitXmlStyleReporter: def __init__(self, file): self.f = open(file, "w"); def begin(self): self.f.write('\n') self.f.write('\n') def report(self, name, result): parts = name.split(".") method = parts[-1] module = '.'.join(parts[0:-1]) self.f.write('\n' % (module, method, result.time)) if result.failed: escaped_type = cgi.escape(str(result.exception_type)) escaped_message = cgi.escape(str(result.exception_message)) self.f.write('\n' % (escaped_type, escaped_message)) self.f.write('\n') self.f.write('\n') if result.skipped: self.f.write('\n') self.f.write('\n') def end(self): self.f.write('\n') self.f.close() class Interceptor: def __init__(self): self.newline = False self.indent = False self.passthrough = True self.dirty = False self.last = None def begin(self): self.newline = True self.indent = True self.passthrough = False self.dirty = False self.last = None def reset(self): self.newline = False self.indent = False self.passthrough = True class StreamWrapper: def __init__(self, interceptor, stream, prefix=" "): self.interceptor = interceptor self.stream = stream self.prefix = prefix def fileno(self): return self.stream.fileno() def isatty(self): return self.stream.isatty() def write(self, s): if self.interceptor.passthrough: self.stream.write(s) return if s: self.interceptor.dirty = True if self.interceptor.newline: self.interceptor.newline = False self.stream.write(" %s\n" % colorize_word("start")) self.interceptor.indent = True if self.interceptor.indent: self.stream.write(self.prefix) if s.endswith("\n"): s = s.replace("\n", "\n%s" % self.prefix)[:-2] self.interceptor.indent = True else: s = s.replace("\n", "\n%s" % self.prefix) self.interceptor.indent = False self.stream.write(s) if s: self.interceptor.last = s[-1] def flush(self): self.stream.flush() interceptor = Interceptor() out_wrp = StreamWrapper(interceptor, sys.stdout) err_wrp = StreamWrapper(interceptor, sys.stderr) out = sys.stdout err = sys.stderr sys.stdout = out_wrp sys.stderr = err_wrp class PatternFilter(Filter): def __init__(self, *patterns): Filter.__init__(self, patterns) self.patterns = patterns def filter(self, record): if not self.patterns: return True for p in self.patterns: if match(record.name, p): return True return False root = getLogger() handler = StreamHandler(sys.stdout) filter = PatternFilter(*config.log_categories) handler.addFilter(filter) handler.setFormatter(Formatter("%(asctime)s %(levelname)s %(message)s")) root.addHandler(handler) root.setLevel(WARN) log = getLogger("proton.test") PASS = "pass" SKIP = "skip" FAIL = "fail" class Runner: def __init__(self): self.exception = None self.exception_phase_name = None self.skip = False def passed(self): return not self.exception def skipped(self): return self.skip def failed(self): return self.exception and not self.skip def halt(self): """determines if the overall test execution should be allowed to continue to the next phase""" return self.exception or self.skip def run(self, phase_name, phase): """invokes a test-phase method (which can be the test method itself or a setUp/tearDown method). If the method raises an exception the exception is examined to see if the exception should be classified as a 'skipped' test""" # we don't try to catch exceptions for jython because currently a # jython bug will prevent the java portion of the stack being # stored with the exception info in the sys module if opts.bare: phase() else: try: phase() except KeyboardInterrupt: raise except: self.exception_phase_name = phase_name self.exception = sys.exc_info() exception_type = self.exception[0] self.skip = getattr(exception_type, "skipped", False) or issubclass(exception_type, SkipTest) def status(self): if self.passed(): return PASS elif self.skipped(): return SKIP elif self.failed(): return FAIL else: return None def get_formatted_exception_trace(self): if self.exception: if self.skip: # format skipped tests without a traceback output = indent("".join(traceback.format_exception_only(*self.exception[:2]))).rstrip() else: output = "Error during %s:" % self.exception_phase_name lines = traceback.format_exception(*self.exception) val = self.exception[1] reflect = False if val and hasattr(val, "getStackTrace"): jlines = [] for frame in val.getStackTrace(): if reflect and frame.getClassName().startswith("org.python."): # this is a heuristic to eliminate the jython portion of # the java stack trace if not opts.javatrace: break jlines.append(" %s\n" % frame.toString()) if frame.getClassName().startswith("java.lang.reflect"): reflect = True else: reflect = False lines.extend(jlines) output += indent("".join(lines)).rstrip() return output def get_exception_type(self): if self.exception: return self.exception[0] else: return None def get_exception_message(self): if self.exception: return self.exception[1] else: return None ST_WIDTH = 8 def run_test(name, test, config): patterns = filter.patterns level = root.level filter.patterns = config.log_categories root.setLevel(config.log_level) parts = name.split(".") line = None output = "" for part in parts: if line: if len(line) + len(part) >= (WIDTH - ST_WIDTH - 1): output += "%s. \\\n" % line line = " %s" % part else: line = "%s.%s" % (line, part) else: line = part if line: output += "%s %s" % (line, (((WIDTH - ST_WIDTH) - len(line))*".")) sys.stdout.write(output) sys.stdout.flush() interceptor.begin() start = time.time() try: runner = test() finally: interceptor.reset() end = time.time() if interceptor.dirty: if interceptor.last != "\n": sys.stdout.write("\n") sys.stdout.write(output) print(" %s" % colorize_word(runner.status())) if runner.failed() or runner.skipped(): print(runner.get_formatted_exception_trace()) root.setLevel(level) filter.patterns = patterns return TestResult(end - start, runner.passed(), runner.skipped(), runner.failed(), runner.get_exception_type(), runner.get_exception_message(), runner.get_formatted_exception_trace()) class TestResult: def __init__(self, time, passed, skipped, failed, exception_type, exception_message, formatted_exception_trace): self.time = time self.passed = passed self.skipped = skipped self.failed = failed self.exception_type = exception_type self.exception_message = exception_message self.formatted_exception_trace = formatted_exception_trace class FunctionTest: def __init__(self, test): self.test = test def name(self): return "%s.%s" % (self.test.__module__, self.test.__name__) def run(self): return run_test(self.name(), self._run, config) def _run(self): runner = Runner() runner.run("test", lambda: self.test(config)) return runner def __repr__(self): return "FunctionTest(%r)" % self.test class MethodTest: def __init__(self, cls, method): self.cls = cls self.method = method def name(self): return "%s.%s.%s" % (self.cls.__module__, self.cls.__name__, self.method) def run(self): return run_test(self.name(), self._run, config) def _run(self): runner = Runner() inst = self.cls(self.method) test = getattr(inst, self.method) if hasattr(inst, "configure"): runner.run("configure", lambda: inst.configure(config)) if runner.halt(): return runner if hasattr(inst, "setUp"): runner.run("setup", inst.setUp) if runner.halt(): return runner runner.run("test", test) if hasattr(inst, "tearDown"): runner.run("teardown", inst.tearDown) return runner def __repr__(self): return "MethodTest(%r, %r)" % (self.cls, self.method) class PatternMatcher: def __init__(self, *patterns): self.patterns = patterns def matches(self, name): for p in self.patterns: if match(name, p): return True return False class FunctionScanner(PatternMatcher): def inspect(self, obj): return type(obj) == types.FunctionType and self.matches(obj.__name__) def descend(self, func): # the None is required for older versions of python return; yield None def extract(self, func): yield FunctionTest(func) class ClassScanner(PatternMatcher): def inspect(self, obj): return type(obj) in CLASS_TYPES and self.matches(obj.__name__) def descend(self, cls): # the None is required for older versions of python return; yield None def extract(self, cls): names = dir(cls) names.sort() for name in names: obj = getattr(cls, name) if hasattr(obj, '__call__') and name.startswith("test"): yield MethodTest(cls, name) class ModuleScanner: def inspect(self, obj): return type(obj) == types.ModuleType def descend(self, obj): names = dir(obj) names.sort() for name in names: yield getattr(obj, name) def extract(self, obj): # the None is required for older versions of python return; yield None class Harness: def __init__(self): self.scanners = [ ModuleScanner(), ClassScanner("*Test", "*Tests", "*TestCase"), FunctionScanner("test_*") ] self.tests = [] self.scanned = [] def scan(self, *roots): objects = list(roots) while objects: obj = objects.pop(0) for s in self.scanners: if s.inspect(obj): self.tests.extend(s.extract(obj)) for child in s.descend(obj): if not (child in self.scanned or child in objects): objects.append(child) self.scanned.append(obj) modules = opts.modules if not modules: modules.extend(["proton_tests"]) h = Harness() for name in modules: m = __import__(name, None, None, ["dummy"]) h.scan(m) filtered = [t for t in h.tests if is_included(t.name())] ignored = [t for t in h.tests if is_ignored(t.name())] total = len(filtered) + len(ignored) if opts.xml and not list_only: xmlr = JunitXmlStyleReporter(opts.xml); xmlr.begin(); else: xmlr = None def runthrough(): passed = 0 failed = 0 skipped = 0 start = time.time() for t in filtered: if list_only: print(t.name()) else: st = t.run() if xmlr: xmlr.report(t.name(), st) if st.passed: passed += 1 elif st.skipped: skipped += 1 elif st.failed: failed += 1 if opts.hoe: break end = time.time() run = passed + failed if not list_only: if passed: _pass = "pass" else: _pass = "fail" if failed: outcome = "fail" else: outcome = "pass" if ignored: ign = "ignored" else: ign = "pass" if skipped: skip = "skip" else: skip = "pass" sys.stdout.write(colorize("Totals: ", 1)) totals = [colorize_word("total", "%s tests" % total), colorize_word(_pass, "%s passed" % passed), colorize_word(skip, "%s skipped" % skipped), colorize_word(ign, "%s ignored" % len(ignored)), colorize_word(outcome, "%s failed" % failed)] sys.stdout.write(", ".join(totals)) if opts.hoe and failed > 0: print(" -- (halted after %s)" % run) else: print("") if opts.time and run > 0: sys.stdout.write(colorize("Timing:", 1)) timing = [colorize_word("elapsed", "%.2fs elapsed" % (end - start)), colorize_word("average", "%.2fs average" % ((end - start)/run))] print(", ".join(timing)) if xmlr: xmlr.end() return failed limit = opts.count count = 0 failures = False while limit == 0 or count < limit: count += 1 if runthrough(): failures = True if count > 1: print(" -- (failures after %s runthroughs)" % count) else: continue if failures: sys.exit(1) else: sys.exit(0) qpid-proton-0.14.0/tests/resources/0000755000175000017500000000000012770711161016501 5ustar danieldanielqpid-proton-0.14.0/tests/resources/logging.properties0000644000175000017500000000220612770711161022245 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # handlers = java.util.logging.ConsoleHandler java.util.logging.ConsoleHandler.level = ALL java.util.logging.ConsoleHandler.formatter = java.util.logging.SimpleFormatter # Note: the following line forces log statements to appear on a single line # when running on JDK 1.7 and later java.util.logging.SimpleFormatter.format = %1$tF %1$tT.%tL %4$s %5$s%n .level = INFO qpid-proton-0.14.0/tests/ruby/0000755000175000017500000000000012770711161015450 5ustar danieldanielqpid-proton-0.14.0/tests/ruby/proton_tests/0000755000175000017500000000000012770711161020213 5ustar danieldanielqpid-proton-0.14.0/tests/ruby/proton_tests/interop.rb0000755000175000017500000001051512770711161022225 0ustar danieldaniel#!/usr/bin/env ruby require 'test/unit' require 'qpid_proton' if ((RUBY_VERSION.split(".").map {|x| x.to_i} <=> [1, 9]) < 0) require 'pathname' class File def self.absolute_path(name) return Pathname.new(name).realpath end end end class InteropTest < Test::Unit::TestCase Data = Qpid::Proton::Codec::Data Message = Qpid::Proton::Message def setup @data = Data.new @message = Message.new end # Walk up the directory tree to find the tests directory. def get_data(name) path = File.absolute_path(__FILE__) while path and File.basename(path) != "tests" do path = File.dirname(path); end path = File.join(path,"interop") raise "Can't find test/interop directory from #{__FILE__}" unless File.directory?(path) path = File.join(path,"#{name}.amqp") File.open(path, "rb") { |f| f.read } end # Decode encoded bytes as a Data object def decode_data(encoded) buffer = encoded while buffer.size > 0 n = @data.decode(buffer) buffer = buffer[n..-1] end @data.rewind reencoded = @data.encode # Test the round-trip re-encoding gives the same result. assert_equal(encoded, reencoded) end def decode_data_file(name) decode_data(get_data(name)); end def decode_message_file(name) message = Message.new() message.decode(self.get_data(name)) self.decode_data(message.body) end def assert_next(type, value) assert @data.next assert_equal(type, @data.type) assert_equal(value, type.get(@data)) end def assert_array_next(expected, header) assert_next(Qpid::Proton::Codec::ARRAY, expected) result = @data.type.get(@data) assert_equal(result.proton_array_header, header) end def test_message decode_message_file("message") assert_next(Qpid::Proton::Codec::STRING, "hello") assert !@data.next end def test_primitives decode_data_file("primitives") assert_next(Qpid::Proton::Codec::BOOL, true) assert_next(Qpid::Proton::Codec::BOOL, false) assert_next(Qpid::Proton::Codec::UBYTE, 42) assert_next(Qpid::Proton::Codec::USHORT, 42) assert_next(Qpid::Proton::Codec::SHORT, -42) assert_next(Qpid::Proton::Codec::UINT, 12345) assert_next(Qpid::Proton::Codec::INT, -12345) assert_next(Qpid::Proton::Codec::ULONG, 12345) assert_next(Qpid::Proton::Codec::LONG, -12345) assert_next(Qpid::Proton::Codec::FLOAT, 0.125) assert_next(Qpid::Proton::Codec::DOUBLE, 0.125) assert !@data.next end def test_strings decode_data_file("strings") assert_next(Qpid::Proton::Codec::BINARY, "abc\0defg") assert_next(Qpid::Proton::Codec::STRING, "abcdefg") assert_next(Qpid::Proton::Codec::SYMBOL, "abcdefg") assert_next(Qpid::Proton::Codec::BINARY, "") assert_next(Qpid::Proton::Codec::STRING, "") assert_next(Qpid::Proton::Codec::SYMBOL, "") assert !@data.next end def test_described decode_data_file("described") assert_next(Qpid::Proton::Codec::DESCRIBED, Qpid::Proton::Types::Described.new("foo-descriptor", "foo-value")) assert(@data.described?) assert_next(Qpid::Proton::Codec::DESCRIBED, Qpid::Proton::Types::Described.new(12, 13)) assert(@data.described?) assert !@data.next end def test_described_array decode_data_file("described_array") assert_array_next((0...10).to_a, Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::INT, "int-array")) end def test_arrays decode_data_file("arrays") assert_array_next((0...100).to_a, Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::INT)) assert_array_next(["a", "b", "c"], Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::STRING)) assert_array_next([], Qpid::Proton::Types::ArrayHeader.new(Qpid::Proton::Codec::INT)) assert !@data.next end def test_lists decode_data_file("lists") assert_next(Qpid::Proton::Codec::LIST, [32, "foo", true]) assert_next(Qpid::Proton::Codec::LIST, []) assert !@data.next end def test_maps decode_data_file("maps") assert_next(Qpid::Proton::Codec::MAP, {"one" => 1, "two" => 2, "three" => 3 }) assert_next(Qpid::Proton::Codec::MAP, {1 => "one", 2 => "two", 3 => "three"}) assert_next(Qpid::Proton::Codec::MAP, {}) assert !@data.next end end qpid-proton-0.14.0/tests/ruby/proton_tests/smoke.rb0000755000175000017500000000230312770711161021657 0ustar danieldaniel#!/usr/bin/env ruby require 'test/unit' require 'qpid_proton' class SmokeTest < Test::Unit::TestCase Messenger = Qpid::Proton::Messenger::Messenger Message = Qpid::Proton::Message def setup @server = Messenger.new() @client = Messenger.new() @server.blocking = false @client.blocking = false @server.subscribe("~0.0.0.0:12345") @server.start() @client.start() pump() end def pump while (@server.work(0) or @client.work(0)) do end end def teardown @server.stop() @client.stop() pump() assert @client.stopped? assert @server.stopped? end def testSmoke(count=10) msg = Message.new() msg.address = "0.0.0.0:12345" @server.receive() count.times {|i| msg.body = "Hello World! #{i}" @client.put(msg) } msg2 = Message.new() count.times {|i| if (@server.incoming == 0) then pump() end @server.get(msg2) assert msg2.body == "Hello World! #{i}" } assert(@client.outgoing == 0, "Expected 0 outgoing messages, found #{@client.outgoing}") assert(@server.incoming == 0, "Expected 0 incoming messages, found #{@server.incoming}") end end qpid-proton-0.14.0/tests/ruby/proton-test0000755000175000017500000000023312770711161017672 0ustar danieldaniel#!/usr/bin/env ruby if RUBY_VERSION < "1.9" require 'rubygems' end require 'test/unit' require 'proton_tests/interop.rb' require 'proton_tests/smoke.rb' qpid-proton-0.14.0/tests/smoke/0000755000175000017500000000000012770711161015605 5ustar danieldanielqpid-proton-0.14.0/tests/smoke/recv.php0000755000175000017500000000062512770711161017263 0ustar danieldaniel#!/usr/bin/env php incoming_window = 10; $message = new Message(); $address = $argv[1]; if (!$address) { $address = "~0.0.0.0"; } $messenger->subscribe($address); $messenger->start(); while (true) { $messenger->recv(); $messenger->get($message); print "Got: $message\n"; $messenger->accept(); } $messenger->stop(); ?>qpid-proton-0.14.0/tests/smoke/recv.pl0000755000175000017500000000102412770711161017101 0ustar danieldaniel#!/usr/bin/env perl require 'qpid_proton.pm'; my $messenger = qpid::proton::Messenger->new(); $messenger->set_incoming_window(1); my $message = qpid::proton::Message->new(); my $address = $ARGV[0]; $address = "~0.0.0.0" if !defined $address; $messenger->subscribe($address); $messenger->start(); while (true) { my $err = $messenger->receive(); # XXX: no exceptions! die $messenger->get_error() if $err < 0; $messenger->get($message); print "Got: $message\n"; $messenger->accept(); } $messenger->stop(); qpid-proton-0.14.0/tests/smoke/recv.py0000755000175000017500000000063012770711161017120 0ustar danieldaniel#!/usr/bin/env python from __future__ import print_function import sys from proton import * messenger = Messenger() messenger.incoming_window = 1 message = Message() address = "~0.0.0.0" if len(sys.argv) > 1: address = sys.argv[1] messenger.subscribe(address) messenger.start() while True: messenger.recv() messenger.get(message) print("Got: %s" % message) messenger.accept() messenger.stop() qpid-proton-0.14.0/tests/smoke/recv.rb0000755000175000017500000000062612770711161017100 0ustar danieldaniel#!/usr/bin/env ruby require 'qpid_proton.rb' messenger = Qpid::Proton::Messenger.new() messenger.incoming_window = 1 message = Qpid::Proton::Message.new() address = ARGV[0] if not address then address = "~0.0.0.0" end messenger.subscribe(address) messenger.start() while (true) do messenger.receive() messenger.get(message) print "Got: #{message}\n" messenger.accept() end messenger.stop() qpid-proton-0.14.0/tests/smoke/send.php0000755000175000017500000000105712770711161017255 0ustar danieldaniel#!/usr/bin/env php outgoing_window = 10; $message = new Message(); $address = $argv[1]; if (!$address) { $address = "0.0.0.0"; } $message->address = $address; $message->properties = Array("binding" => "php", "version" => phpversion()); $message->body = "Hello World!"; $messenger->start(); $tracker = $messenger->put($message); print "Put: $message\n"; $messenger->send(); print "Status: " . $messenger->status($tracker) . "\n"; $messenger->stop(); ?>qpid-proton-0.14.0/tests/smoke/send.pl0000755000175000017500000000075712770711161017107 0ustar danieldaniel#!/usr/bin/env perl require 'qpid_proton.pm'; my $messenger = qpid::proton::Messenger->new(); $messenger->set_outgoing_window(10); my $message = qpid::proton::Message->new(); my $address = $ARGV[0]; $address = "0.0.0.0" if !defined $address; $message->set_address($address); # how do we set properties and body? $messenger->start(); my $tracker = $messenger->put($message); print "Put: $message\n"; $messenger->send(); print "Status: ", $messenger->status($tracker), "\n"; $messenger->stop(); qpid-proton-0.14.0/tests/smoke/send.py0000755000175000017500000000104212770711161017110 0ustar danieldaniel#!/usr/bin/env python from __future__ import print_function import sys from proton import * messenger = Messenger() messenger.outgoing_window = 10 message = Message() address = "0.0.0.0" if len(sys.argv) > 1: address = sys.argv[1] message.address = address message.properties = {u"binding": u"python", u"version": sys.version} message.body = u"Hello World!" messenger.start() tracker = messenger.put(message) print("Put: %s" % message) messenger.send() print("Status: %s" % messenger.status(tracker)) messenger.stop() qpid-proton-0.14.0/tests/smoke/send.rb0000755000175000017500000000103012770711161017060 0ustar danieldaniel#!/usr/bin/env ruby require 'qpid_proton.rb' messenger = Qpid::Proton::Messenger.new() messenger.outgoing_window = 10 message = Qpid::Proton::Message.new() address = ARGV[0] if not address then address = "0.0.0.0" end message.address = address message.properties = {"binding" => "ruby", "version" => "#{RUBY_VERSION} #{RUBY_PLATFORM}"} message.body = "Hello World!" messenger.start() tracker = messenger.put(message) print "Put: #{message}\n" messenger.send() print "Status: ", messenger.status(tracker), "\n" messenger.stop() qpid-proton-0.14.0/tests/tools/0000755000175000017500000000000012770711161015627 5ustar danieldanielqpid-proton-0.14.0/tests/tools/apps/0000755000175000017500000000000012770711161016572 5ustar danieldanielqpid-proton-0.14.0/tests/tools/apps/README.txt0000644000175000017500000000103512770711161020267 0ustar danieldanielThis directory contains applications built using proton. These applications are used by the testbed for soak tests. See the "soak.py" file for the tests that utilize these applications. These applications can be used standalone to generate or consume message traffic. Contents: msgr-send - this Messenger-based application generates message traffic, and can be configured to consume responses. msgr-recv - this Messenger-based application consumes message traffic, and can be configured to forward or reply to received messages. qpid-proton-0.14.0/tests/tools/apps/c/0000755000175000017500000000000012770711161017014 5ustar danieldanielqpid-proton-0.14.0/tests/tools/apps/c/msgr-common.c0000644000175000017500000001125612770711161021423 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "msgr-common.h" #include #include #include #include #include void msgr_die(const char *file, int line, const char *message) { fprintf(stderr, "%s:%i: %s\n", file, line, message); exit(1); } //sigh - would be nice if proton exported pn_strdup() char *msgr_strdup( const char *src ) { char *r = NULL; if (src) { r = (char *) malloc(sizeof(char) * (strlen(src) + 1)); if (r) strcpy(r,src); } return r; } pn_timestamp_t msgr_now() { // from "pncompat/misc_funcs.inc" return time_now(); } void addresses_init( Addresses_t *a ) { a->size = 10; // whatever a->count = 0; a->addresses = (const char **) calloc( a->size, sizeof(const char *)); check(a->addresses, "malloc failure"); } void addresses_free( Addresses_t *a ) { if (a->addresses) { int i; for (i = 0; i < a->count; i++) if (a->addresses[i]) free( (void *)a->addresses[i] ); free( a->addresses ); a->addresses = NULL; } } void addresses_add( Addresses_t *a, const char *addr ) { if (a->count == a->size) { a->size += 10; a->addresses = (const char **) realloc( a->addresses, a->size * sizeof(const char *) ); check( a->addresses, "malloc failure" ); int i; for (i = a->count; i < a->size; i++) a->addresses[i] = NULL; } a->addresses[a->count] = msgr_strdup(addr); check( a->addresses[a->count], "malloc failure" ); a->count++; } // merge a comma-separated list of addresses void addresses_merge( Addresses_t *a, const char *list ) { char *const l = msgr_strdup(list); check( l, "malloc failure" ); char *addr = l; while (addr && *addr) { char *comma = strchr( addr, ',' ); if (comma) { *comma++ = '\0'; } addresses_add( a, addr ); addr = comma; } free(l); } void statistics_start( Statistics_t *s ) { s->latency_samples = 0; s->latency_total = s->latency_min = s->latency_max = 0.0; s->start = msgr_now(); } void statistics_msg_received( Statistics_t *s, pn_message_t *message ) { pn_timestamp_t ts = pn_message_get_creation_time( message ); if (ts) { double l = (double)(msgr_now() - ts); if (l > 0) { s->latency_total += l; if (++s->latency_samples == 1) { s->latency_min = s->latency_max = l; } else { if (s->latency_min > l) s->latency_min = l; if (s->latency_max < l) s->latency_max = l; } } } } void statistics_report( Statistics_t *s, uint64_t sent, uint64_t received ) { pn_timestamp_t end = msgr_now() - s->start; double secs = end/(double)1000.0; fprintf(stdout, "Messages sent: %" PRIu64 " recv: %" PRIu64 "\n", sent, received ); fprintf(stdout, "Total time: %f sec\n", secs ); fprintf(stdout, "Throughput: %f msgs/sec\n", (secs != 0.0) ? (double)sent/secs : 0); fprintf(stdout, "Latency (sec): %f min %f max %f avg\n", s->latency_min/1000.0, s->latency_max/1000.0, (s->latency_samples) ? (s->latency_total/s->latency_samples)/1000.0 : 0); } void parse_password( const char *input, char **password ) { if (strncmp( input, "pass:", 5 ) == 0) { // password provided on command line (not secure, shows up in 'ps') *password = msgr_strdup( input + 5 ); } else { // input assumed to be file containing password FILE *f = fopen( input, "r" ); check( f, "Cannot open password file\n" ); *password = (char *)malloc(256); // 256 should be enough for anybody! check( *password, "malloc failure" ); int rc = fscanf( f, "%255s", *password ); check( rc == 1, "Cannot read password from file\n" ); fclose(f); } } static int log = 0; void enable_logging() { log = 1; } void LOG( const char *fmt, ... ) { if (log) { va_list ap; va_start(ap, fmt); vfprintf( stdout, fmt, ap ); va_end(ap); } } qpid-proton-0.14.0/tests/tools/apps/c/msgr-common.h0000644000175000017500000000471512770711161021432 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "pncompat/misc_defs.h" #if defined(USE_INTTYPES) #ifdef __cplusplus #define __STDC_FORMAT_MACROS #endif #include #endif #ifdef _MSC_VER #if !defined(PRIu64) #define PRIu64 "I64u" #endif #if !defined(SCNu64) #define SCNu64 "I64u" #endif #endif /* If still not defined, best guess */ #if !defined(SCNu64) #define SCNu64 "ul" #endif #if !defined(PRIu64) #define PRIu64 "ul" #endif #include "proton/types.h" #include "proton/message.h" void msgr_die(const char *file, int line, const char *message); char *msgr_strdup( const char *src ); pn_timestamp_t msgr_now(void); void parse_password( const char *, char ** ); #define check_messenger(m) \ { check(pn_messenger_errno(m) == 0, pn_error_text(pn_messenger_error(m))) } #define check( expression, message ) \ { if (!(expression)) msgr_die(__FILE__,__LINE__, message); } // manage an ordered list of addresses typedef struct { const char **addresses; int size; // room in 'addresses' int count; // # entries } Addresses_t; #define NEXT_ADDRESS(a, i) (((i) + 1) % (a).count) void addresses_init( Addresses_t *a ); void addresses_free( Addresses_t *a ); void addresses_add( Addresses_t *a, const char *addr ); void addresses_merge( Addresses_t *a, const char *list ); // Statistics handling typedef struct { pn_timestamp_t start; uint64_t latency_samples; double latency_total; double latency_min; double latency_max; } Statistics_t; void statistics_start( Statistics_t *s ); void statistics_msg_received( Statistics_t *s, pn_message_t *message ); void statistics_report( Statistics_t *s, uint64_t sent, uint64_t received ); void enable_logging(void); void LOG( const char *fmt, ... ); qpid-proton-0.14.0/tests/tools/apps/c/msgr-recv.c0000644000175000017500000002354512770711161021076 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "msgr-common.h" #include "proton/message.h" #include "proton/messenger.h" #include "proton/error.h" #include #include #include #include typedef struct { Addresses_t subscriptions; uint64_t msg_count; int recv_count; int incoming_window; int timeout; // seconds unsigned int report_interval; // in seconds int outgoing_window; Addresses_t forwarding_targets; int reply; const char *name; const char *ready_text; char *certificate; char *privatekey; // used to sign certificate char *password; // for private key file char *ca_db; // trusted CA database } Options_t; static void usage(int rc) { printf("Usage: msgr-recv [OPTIONS] \n" " -a [,]* \tAddresses to listen on [amqp://~0.0.0.0]\n" " -c # \tNumber of messages to receive before exiting [0=forever]\n" " -b # \tArgument to Messenger::recv(n) [2048]\n" " -w # \tSize for incoming window [0]\n" " -t # \tInactivity timeout in seconds, -1 = no timeout [-1]\n" " -e # \t# seconds to report statistics, 0 = end of test [0] *TBD*\n" " -R \tSend reply if 'reply-to' present\n" " -W # \t# outgoing window size [0]\n" " -F [,]* \tAddresses used for forwarding received messages\n" " -N \tSet the container name to \n" " -X \tPrint '\\n' to stdout after all subscriptions are created\n" " -V \tEnable debug logging\n" " SSL options:\n" " -T \tDatabase of trusted CA certificates for validating peer\n" " -C \tFile containing self-identifying certificate\n" " -K \tFile containing private key used to sign certificate\n" " -P [pass:|path] \tPassword to unlock private key file.\n" ); exit(rc); } static void parse_options( int argc, char **argv, Options_t *opts ) { int c; opterr = 0; memset( opts, 0, sizeof(*opts) ); opts->recv_count = -1; opts->timeout = -1; addresses_init(&opts->subscriptions); addresses_init(&opts->forwarding_targets); while ((c = getopt(argc, argv, "a:c:b:w:t:e:RW:F:VN:X:T:C:K:P:")) != -1) { switch (c) { case 'a': addresses_merge( &opts->subscriptions, optarg ); break; case 'c': if (sscanf( optarg, "%" SCNu64, &opts->msg_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'b': if (sscanf( optarg, "%d", &opts->recv_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'w': if (sscanf( optarg, "%d", &opts->incoming_window ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 't': if (sscanf( optarg, "%d", &opts->timeout ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } if (opts->timeout > 0) opts->timeout *= 1000; break; case 'e': if (sscanf( optarg, "%u", &opts->report_interval ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'R': opts->reply = 1; break; case 'W': if (sscanf( optarg, "%d", &opts->outgoing_window ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'F': addresses_merge( &opts->forwarding_targets, optarg ); break; case 'V': enable_logging(); break; case 'N': opts->name = optarg; break; case 'X': opts->ready_text = optarg; break; case 'T': opts->ca_db = optarg; break; case 'C': opts->certificate = optarg; break; case 'K': opts->privatekey = optarg; break; case 'P': parse_password( optarg, &opts->password ); break; default: usage(1); } } // default subscription if none specified if (opts->subscriptions.count == 0) addresses_add( &opts->subscriptions, "amqp://~0.0.0.0" ); } int main(int argc, char** argv) { Options_t opts; Statistics_t stats; uint64_t sent = 0; uint64_t received = 0; int forwarding_index = 0; int rc; pn_message_t *message; pn_messenger_t *messenger; parse_options( argc, argv, &opts ); const int forward = opts.forwarding_targets.count != 0; message = pn_message(); messenger = pn_messenger( opts.name ); /* load the various command line options if they're set */ if (opts.certificate) { rc = pn_messenger_set_certificate(messenger, opts.certificate); check_messenger(messenger); check( rc == 0, "Failed to set certificate" ); } if (opts.privatekey) { rc = pn_messenger_set_private_key(messenger, opts.privatekey); check_messenger(messenger); check( rc == 0, "Failed to set private key" ); } if (opts.password) { rc = pn_messenger_set_password(messenger, opts.password); check_messenger(messenger); check( rc == 0, "Failed to set password" ); } if (opts.ca_db) { rc = pn_messenger_set_trusted_certificates(messenger, opts.ca_db); check_messenger(messenger); check( rc == 0, "Failed to set trusted CA database" ); } if (opts.incoming_window) { // RAFI: seems to cause receiver to hang: pn_messenger_set_incoming_window( messenger, opts.incoming_window ); } pn_messenger_set_timeout( messenger, opts.timeout ); pn_messenger_start(messenger); check_messenger(messenger); int i; for (i = 0; i < opts.subscriptions.count; i++) { pn_messenger_subscribe(messenger, opts.subscriptions.addresses[i]); check_messenger(messenger); LOG("Subscribing to '%s'\n", opts.subscriptions.addresses[i]); } // hack to let test scripts know when the receivers are ready (so // that the senders may be started) if (opts.ready_text) { fprintf(stdout, "%s\n", opts.ready_text); fflush(stdout); } while (!opts.msg_count || received < opts.msg_count) { LOG("Calling pn_messenger_recv(%d)\n", opts.recv_count); rc = pn_messenger_recv(messenger, opts.recv_count); check_messenger(messenger); check(rc == 0 || (opts.timeout == 0 && rc == PN_TIMEOUT), "pn_messenger_recv() failed"); // start the timer only after receiving the first msg if (received == 0) statistics_start( &stats ); LOG("Messages on incoming queue: %d\n", pn_messenger_incoming(messenger)); while (pn_messenger_incoming(messenger)) { pn_messenger_get(messenger, message); check_messenger(messenger); received++; // TODO: header decoding? // uint64_t id = pn_message_get_correlation_id( message ).u.as_ulong; statistics_msg_received( &stats, message ); if (opts.reply) { const char *reply_addr = pn_message_get_reply_to( message ); if (reply_addr) { LOG("Replying to: %s\n", reply_addr ); pn_message_set_address( message, reply_addr ); pn_message_set_creation_time( message, msgr_now() ); pn_messenger_put(messenger, message); sent++; } } if (forward) { const char *forward_addr = opts.forwarding_targets.addresses[forwarding_index]; forwarding_index = NEXT_ADDRESS(opts.forwarding_targets, forwarding_index); LOG("Forwarding to: %s\n", forward_addr ); pn_message_set_address( message, forward_addr ); pn_message_set_reply_to( message, NULL ); // else points to origin sender pn_message_set_creation_time( message, msgr_now() ); pn_messenger_put(messenger, message); sent++; } } LOG("Messages received=%llu sent=%llu\n", received, sent); } // this will flush any pending sends if (pn_messenger_outgoing(messenger) > 0) { LOG("Calling pn_messenger_send()\n"); rc = pn_messenger_send(messenger, -1); check_messenger(messenger); check(rc == 0, "pn_messenger_send() failed"); } rc = pn_messenger_stop(messenger); check(rc == 0, "pn_messenger_stop() failed"); check_messenger(messenger); statistics_report( &stats, sent, received ); pn_messenger_free(messenger); pn_message_free(message); addresses_free( &opts.subscriptions ); addresses_free( &opts.forwarding_targets ); return 0; } qpid-proton-0.14.0/tests/tools/apps/c/msgr-send.c0000644000175000017500000002611212770711161021061 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "msgr-common.h" #include "proton/message.h" #include "proton/messenger.h" #include "proton/error.h" #include #include #include #include typedef struct { Addresses_t targets; uint64_t msg_count; uint32_t msg_size; // of body uint32_t send_batch; int outgoing_window; unsigned int report_interval; // in seconds //Addresses_t subscriptions; //Addresses_t reply_tos; int get_replies; int timeout; // in seconds int incoming_window; int recv_count; const char *name; char *certificate; char *privatekey; // used to sign certificate char *password; // for private key file char *ca_db; // trusted CA database } Options_t; static void usage(int rc) { printf("Usage: msgr-send [OPTIONS] \n" " -a [,]* \tThe target address [amqp[s]://domain[/name]]\n" " -c # \tNumber of messages to send before exiting [0=forever]\n" " -b # \tSize of message body in bytes [1024]\n" " -p # \tSend batches of # messages (wait for replies before sending next batch if -R) [1024]\n" " -w # \t# outgoing window size [0]\n" " -e # \t# seconds to report statistics, 0 = end of test [0]\n" " -R \tWait for a reply to each sent message\n" " -t # \tInactivity timeout in seconds, -1 = no timeout [-1]\n" " -W # \tIncoming window size [0]\n" " -B # \tArgument to Messenger::recv(n) [-1]\n" " -N \tSet the container name to \n" " -V \tEnable debug logging\n" " SSL options:\n" " -T \tDatabase of trusted CA certificates for validating peer\n" " -C \tFile containing self-identifying certificate\n" " -K \tFile containing private key used to sign certificate\n" " -P [pass:|path] \tPassword to unlock private key file.\n" ); //printf("-p \t*TODO* Add N sample properties to each message [3]\n"); exit(rc); } static void parse_options( int argc, char **argv, Options_t *opts ) { int c; opterr = 0; memset( opts, 0, sizeof(*opts) ); opts->msg_size = 1024; opts->send_batch = 1024; opts->timeout = -1; opts->recv_count = -1; addresses_init(&opts->targets); while ((c = getopt(argc, argv, "a:c:b:p:w:e:l:Rt:W:B:VN:T:C:K:P:")) != -1) { switch(c) { case 'a': addresses_merge( &opts->targets, optarg ); break; case 'c': if (sscanf( optarg, "%" SCNu64, &opts->msg_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'b': if (sscanf( optarg, "%u", &opts->msg_size ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'p': if (sscanf( optarg, "%u", &opts->send_batch ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'w': if (sscanf( optarg, "%d", &opts->outgoing_window ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'e': if (sscanf( optarg, "%u", &opts->report_interval ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'R': opts->get_replies = 1; break; case 't': if (sscanf( optarg, "%d", &opts->timeout ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } if (opts->timeout > 0) opts->timeout *= 1000; break; case 'W': if (sscanf( optarg, "%d", &opts->incoming_window ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'B': if (sscanf( optarg, "%d", &opts->recv_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'V': enable_logging(); break; case 'N': opts->name = optarg; break; case 'T': opts->ca_db = optarg; break; case 'C': opts->certificate = optarg; break; case 'K': opts->privatekey = optarg; break; case 'P': parse_password( optarg, &opts->password ); break; default: usage(1); } } // default target if none specified if (opts->targets.count == 0) addresses_add( &opts->targets, "amqp://0.0.0.0" ); } // return the # of reply messages received static int process_replies( pn_messenger_t *messenger, pn_message_t *message, Statistics_t *stats, int max_count) { int received = 0; LOG("Calling pn_messenger_recv(%d)\n", max_count); int rc = pn_messenger_recv( messenger, max_count ); check((rc == 0 || rc == PN_TIMEOUT), "pn_messenger_recv() failed"); LOG("Messages on incoming queue: %d\n", pn_messenger_incoming(messenger)); while (pn_messenger_incoming(messenger)) { pn_messenger_get(messenger, message); check_messenger(messenger); received++; // TODO: header decoding? statistics_msg_received( stats, message ); // uint64_t id = pn_message_get_correlation_id( message ).u.as_ulong; } return received; } int main(int argc, char** argv) { Options_t opts; Statistics_t stats; uint64_t sent = 0; uint64_t received = 0; int target_index = 0; int rc; pn_message_t *message = 0; pn_message_t *reply_message = 0; pn_messenger_t *messenger = 0; parse_options( argc, argv, &opts ); messenger = pn_messenger( opts.name ); if (opts.certificate) { rc = pn_messenger_set_certificate(messenger, opts.certificate); check( rc == 0, "Failed to set certificate" ); } if (opts.privatekey) { rc = pn_messenger_set_private_key(messenger, opts.privatekey); check( rc == 0, "Failed to set private key" ); } if (opts.password) { rc = pn_messenger_set_password(messenger, opts.password); check( rc == 0, "Failed to set password" ); } if (opts.ca_db) { rc = pn_messenger_set_trusted_certificates(messenger, opts.ca_db); check( rc == 0, "Failed to set trusted CA database" ); } if (opts.outgoing_window) { pn_messenger_set_outgoing_window( messenger, opts.outgoing_window ); } pn_messenger_set_timeout( messenger, opts.timeout ); pn_messenger_start(messenger); message = pn_message(); check(message, "failed to allocate a message"); pn_message_set_reply_to(message, "~"); pn_data_t *body = pn_message_body(message); char *data = (char *)calloc(1, opts.msg_size); pn_data_put_binary(body, pn_bytes(opts.msg_size, data)); free(data); pn_atom_t id; id.type = PN_ULONG; #if 0 // TODO: how do we effectively benchmark header processing overhead??? pn_data_t *props = pn_message_properties(message); pn_data_put_map(props); pn_data_enter(props); // //pn_data_put_string(props, pn_bytes(6, "string")); //pn_data_put_string(props, pn_bytes(10, "this is awkward")); // //pn_data_put_string(props, pn_bytes(4, "long")); pn_data_put_long(props, 12345); // //pn_data_put_string(props, pn_bytes(9, "timestamp")); pn_data_put_timestamp(props, (pn_timestamp_t) 54321); pn_data_exit(props); #endif const int get_replies = opts.get_replies; if (get_replies) { // disable the timeout so that pn_messenger_recv() won't block reply_message = pn_message(); check(reply_message, "failed to allocate a message"); } statistics_start( &stats ); while (!opts.msg_count || (sent < opts.msg_count)) { // setup the message to send pn_message_set_address(message, opts.targets.addresses[target_index]); target_index = NEXT_ADDRESS(opts.targets, target_index); id.u.as_ulong = sent; pn_message_set_correlation_id( message, id ); pn_message_set_creation_time( message, msgr_now() ); pn_messenger_put(messenger, message); sent++; if (opts.send_batch && (pn_messenger_outgoing(messenger) >= (int)opts.send_batch)) { if (get_replies) { while (received < sent) { // this will also transmit any pending sent messages received += process_replies( messenger, reply_message, &stats, opts.recv_count ); } } else { LOG("Calling pn_messenger_send()\n"); rc = pn_messenger_send(messenger, -1); check((rc == 0 || rc == PN_TIMEOUT), "pn_messenger_send() failed"); } } check_messenger(messenger); } LOG("Messages received=%llu sent=%llu\n", received, sent); if (get_replies) { // wait for the last of the replies while (received < sent) { int count = process_replies( messenger, reply_message, &stats, opts.recv_count ); check( count > 0 || (opts.timeout == 0), "Error: timed out waiting for reply messages\n"); received += count; LOG("Messages received=%llu sent=%llu\n", received, sent); } } else if (pn_messenger_outgoing(messenger) > 0) { LOG("Calling pn_messenger_send()\n"); rc = pn_messenger_send(messenger, -1); check(rc == 0, "pn_messenger_send() failed"); } rc = pn_messenger_stop(messenger); check(rc == 0, "pn_messenger_stop() failed"); check_messenger(messenger); statistics_report( &stats, sent, received ); pn_messenger_free(messenger); pn_message_free(message); if (reply_message) pn_message_free( reply_message ); addresses_free( &opts.targets ); return 0; } qpid-proton-0.14.0/tests/tools/apps/c/reactor-recv.c0000644000175000017500000003324712770711161021565 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /* * Implements a subset of msgr-recv.c using reactor events. */ #include "proton/message.h" #include "proton/error.h" #include "proton/types.h" #include "proton/reactor.h" #include "proton/handlers.h" #include "proton/engine.h" #include "proton/url.h" #include "msgr-common.h" #include #include #include #include // The exact struct from msgr-recv, mostly fallow. typedef struct { Addresses_t subscriptions; uint64_t msg_count; int recv_count; int incoming_window; int timeout; // seconds unsigned int report_interval; // in seconds int outgoing_window; int reply; const char *name; const char *ready_text; char *certificate; char *privatekey; // used to sign certificate char *password; // for private key file char *ca_db; // trusted CA database } Options_t; static void usage(int rc) { printf("Usage: reactor-recv [OPTIONS] \n" " -c # \tNumber of messages to receive before exiting [0=forever]\n" " -R \tSend reply if 'reply-to' present\n" " -t # \tInactivity timeout in seconds, -1 = no timeout [-1]\n" " -X \tPrint '\\n' to stdout after all subscriptions are created\n" ); exit(rc); } // Global context for this process typedef struct { Options_t *opts; Statistics_t *stats; uint64_t sent; uint64_t received; pn_message_t *message; pn_acceptor_t *acceptor; char *encoded_data; size_t encoded_data_size; int connections; pn_list_t *active_connections; bool shutting_down; pn_handler_t *listener_handler; int quiesce_count; } global_context_t; // Per connection context typedef struct { global_context_t *global; int connection_id; pn_link_t *recv_link; pn_link_t *reply_link; } connection_context_t; static char *ensure_buffer(char *buf, size_t needed, size_t *actual) { char* new_buf; // Make room for the largest message seen so far, plus extra for slight changes in metadata content if (needed + 1024 <= *actual) return buf; needed += 2048; new_buf = (char *) realloc(buf, needed); if (new_buf != NULL) { buf = new_buf; *actual = buf ? needed : 0; } return buf; } void global_shutdown(global_context_t *gc) { if (gc->shutting_down) return; gc->shutting_down = true; pn_acceptor_close(gc->acceptor); size_t n = pn_list_size(gc->active_connections); for (size_t i = 0; i < n; i++) { pn_connection_t *conn = (pn_connection_t *) pn_list_get(gc->active_connections, i); if (!(pn_connection_state(conn) & PN_LOCAL_CLOSED)) { pn_connection_close(conn); } } } connection_context_t *connection_context(pn_handler_t *h) { connection_context_t *p = (connection_context_t *) pn_handler_mem(h); return p; } void connection_context_init(connection_context_t *cc, global_context_t *gc) { cc->global = gc; pn_incref(gc->listener_handler); cc->connection_id = gc->connections++; cc->recv_link = 0; cc->reply_link = 0; } void connection_cleanup(pn_handler_t *h) { connection_context_t *cc = connection_context(h); // Undo pn_incref() from connection_context_init() pn_decref(cc->global->listener_handler); } void connection_dispatch(pn_handler_t *h, pn_event_t *event, pn_event_type_t type) { connection_context_t *cc = connection_context(h); bool replying = cc->global->opts->reply; switch (type) { case PN_LINK_REMOTE_OPEN: { pn_link_t *link = pn_event_link(event); if (pn_link_is_receiver(link)) { check(cc->recv_link == NULL, "Multiple incomming links on one connection"); cc->recv_link = link; pn_connection_t *conn = pn_event_connection(event); pn_list_add(cc->global->active_connections, conn); if (cc->global->shutting_down) { pn_connection_close(conn); break; } if (replying) { // Set up a reply link and defer granting credit to the incoming link pn_connection_t *conn = pn_session_connection(pn_link_session(link)); pn_session_t *ssn = pn_session(conn); pn_session_open(ssn); char name[100]; // prefer a multiplatform uuid generator sprintf(name, "reply_sender_%d", cc->connection_id); cc->reply_link = pn_sender(ssn, name); pn_link_open(cc->reply_link); } else { pn_flowcontroller_t *fc = pn_flowcontroller(1024); pn_handler_add(h, fc); pn_decref(fc); } } } break; case PN_LINK_FLOW: { if (replying) { pn_link_t *reply_link = pn_event_link(event); // pn_flowcontroller handles the non-reply case check(reply_link == cc->reply_link, "internal error"); // Grant the sender as much credit as just given to us for replies int delta = pn_link_credit(reply_link) - pn_link_credit(cc->recv_link); if (delta > 0) pn_link_flow(cc->recv_link, delta); } } break; case PN_DELIVERY: { pn_link_t *recv_link = pn_event_link(event); pn_delivery_t *dlv = pn_event_delivery(event); if (pn_link_is_receiver(recv_link) && !pn_delivery_partial(dlv)) { if (cc->global->received == 0) statistics_start(cc->global->stats); size_t encoded_size = pn_delivery_pending(dlv); cc->global->encoded_data = ensure_buffer(cc->global->encoded_data, encoded_size, &cc->global->encoded_data_size); check(cc->global->encoded_data, "decoding buffer realloc failure"); ssize_t n = pn_link_recv(recv_link, cc->global->encoded_data, encoded_size); check(n == (ssize_t) encoded_size, "message data read fail"); pn_message_t *msg = cc->global->message; int err = pn_message_decode(msg, cc->global->encoded_data, n); check(err == 0, "message decode error"); cc->global->received++; pn_delivery_settle(dlv); statistics_msg_received(cc->global->stats, msg); if (replying) { const char *reply_addr = pn_message_get_reply_to(msg); if (reply_addr) { pn_link_t *rl = cc->reply_link; check(pn_link_credit(rl) > 0, "message received without corresponding reply credit"); LOG("Replying to: %s\n", reply_addr ); pn_message_set_address(msg, reply_addr); pn_message_set_creation_time(msg, msgr_now()); char tag[8]; void *ptr = &tag; *((uint64_t *) ptr) = cc->global->sent; pn_delivery_t *dlv = pn_delivery(rl, pn_dtag(tag, 8)); size_t size = cc->global->encoded_data_size; int err = pn_message_encode(msg, cc->global->encoded_data, &size); check(err == 0, "message encoding error"); pn_link_send(rl, cc->global->encoded_data, size); pn_delivery_settle(dlv); cc->global->sent++; } } } if (cc->global->received >= cc->global->opts->msg_count) { global_shutdown(cc->global); } } break; case PN_CONNECTION_UNBOUND: { pn_connection_t *conn = pn_event_connection(event); pn_list_remove(cc->global->active_connections, conn); pn_connection_release(conn); } break; default: break; } } pn_handler_t *connection_handler(global_context_t *gc) { pn_handler_t *h = pn_handler_new(connection_dispatch, sizeof(connection_context_t), connection_cleanup); connection_context_t *cc = connection_context(h); connection_context_init(cc, gc); return h; } void start_listener(global_context_t *gc, pn_reactor_t *reactor) { check(gc->opts->subscriptions.count > 0, "no listening address"); pn_url_t *listen_url = pn_url_parse(gc->opts->subscriptions.addresses[0]); const char *host = pn_url_get_host(listen_url); const char *port = pn_url_get_port(listen_url); if (port == 0 || strlen(port) == 0) port = "5672"; if (host == 0 || strlen(host) == 0) host = "0.0.0.0"; if (*host == '~') host++; gc->acceptor = pn_reactor_acceptor(reactor, host, port, NULL); check(gc->acceptor, "acceptor creation failed"); pn_url_free(listen_url); } void global_context_init(global_context_t *gc, Options_t *o, Statistics_t *s) { gc->opts = o; gc->stats = s; gc->sent = 0; gc->received = 0; gc->encoded_data_size = 0; gc->encoded_data = 0; gc->message = pn_message(); check(gc->message, "failed to allocate a message"); gc->connections = 0; gc->active_connections = pn_list(PN_OBJECT, 0); gc->acceptor = 0; gc->shutting_down = false; gc->listener_handler = 0; gc->quiesce_count = 0; } global_context_t *global_context(pn_handler_t *h) { return (global_context_t *) pn_handler_mem(h); } void listener_cleanup(pn_handler_t *h) { global_context_t *gc = global_context(h); pn_message_free(gc->message); free(gc->encoded_data); pn_free(gc->active_connections); } void listener_dispatch(pn_handler_t *h, pn_event_t *event, pn_event_type_t type) { global_context_t *gc = global_context(h); if (type == PN_REACTOR_QUIESCED) gc->quiesce_count++; else gc->quiesce_count = 0; switch (type) { case PN_CONNECTION_INIT: { pn_connection_t *connection = pn_event_connection(event); // New incoming connection on listener socket. Give each a separate handler. pn_handler_t *ch = connection_handler(gc); pn_handshaker_t *handshaker = pn_handshaker(); pn_handler_add(ch, handshaker); pn_decref(handshaker); pn_record_t *record = pn_connection_attachments(connection); pn_record_set_handler(record, ch); pn_decref(ch); } break; case PN_REACTOR_QUIESCED: { // Two quiesce in a row means we have been idle for a timout period if (gc->opts->timeout != -1 && gc->quiesce_count > 1) global_shutdown(gc); } break; case PN_REACTOR_INIT: { pn_reactor_t *reactor = pn_event_reactor(event); start_listener(gc, reactor); // hack to let test scripts know when the receivers are ready (so // that the senders may be started) if (gc->opts->ready_text) { fprintf(stdout, "%s\n", gc->opts->ready_text); fflush(stdout); } if (gc->opts->timeout != -1) pn_reactor_set_timeout(pn_event_reactor(event), gc->opts->timeout); } break; case PN_REACTOR_FINAL: { if (gc->received == 0) statistics_start(gc->stats); statistics_report(gc->stats, gc->sent, gc->received); } break; default: break; } } pn_handler_t *listener_handler(Options_t *opts, Statistics_t *stats) { pn_handler_t *h = pn_handler_new(listener_dispatch, sizeof(global_context_t), listener_cleanup); global_context_t *gc = global_context(h); global_context_init(gc, opts, stats); gc->listener_handler = h; return h; } static void parse_options( int argc, char **argv, Options_t *opts ) { int c; opterr = 0; memset( opts, 0, sizeof(*opts) ); opts->recv_count = -1; opts->timeout = -1; addresses_init( &opts->subscriptions); while ((c = getopt(argc, argv, "a:c:b:w:t:e:RW:F:VN:X:T:C:K:P:")) != -1) { switch (c) { case 'a': { // TODO: multiple addresses? char *comma = strchr(optarg, ','); check(comma == 0, "multiple addresses not implemented"); check(opts->subscriptions.count == 0, "multiple addresses not implemented"); addresses_merge( &opts->subscriptions, optarg ); } break; case 'c': if (sscanf( optarg, "%" SCNu64, &opts->msg_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 't': if (sscanf( optarg, "%d", &opts->timeout ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } if (opts->timeout > 0) opts->timeout *= 1000; break; case 'R': opts->reply = 1; break; case 'V': enable_logging(); break; case 'X': opts->ready_text = optarg; break; default: usage(1); } } if (opts->subscriptions.count == 0) addresses_add( &opts->subscriptions, "amqp://~0.0.0.0" ); } int main(int argc, char** argv) { Options_t opts; Statistics_t stats; parse_options( argc, argv, &opts ); pn_reactor_t *reactor = pn_reactor(); // set up default handlers for our reactor pn_handler_t *root = pn_reactor_get_handler(reactor); pn_handler_t *lh = listener_handler(&opts, &stats); pn_handler_add(root, lh); pn_handshaker_t *handshaker = pn_handshaker(); pn_handler_add(root, handshaker); // Omit decrefs else segfault. Not sure why they are necessary // to keep valgrind happy for the connection_handler, but not here. // pn_decref(handshaker); // pn_decref(lh); pn_reactor_run(reactor); pn_reactor_free(reactor); addresses_free( &opts.subscriptions ); return 0; } qpid-proton-0.14.0/tests/tools/apps/c/CMakeLists.txt0000644000175000017500000000376712770711161021571 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include(CheckIncludeFiles) include_directories(${CMAKE_SOURCE_DIR}/examples/c/include) CHECK_INCLUDE_FILES("inttypes.h" INTTYPES_AVAILABLE) if (INTTYPES_AVAILABLE) list(APPEND PLATFORM_DEFINITIONS "USE_INTTYPES") else (INTTYPES_AVAILABLE) if (CMAKE_COMPILER_IS_GNUCC) # since inttypes.h provides portable printf format macros set (COMPILE_WARNING_FLAGS "${COMPILE_WARNING_FLAGS} -Wno-format") endif (CMAKE_COMPILER_IS_GNUCC) endif (INTTYPES_AVAILABLE) add_executable(msgr-recv msgr-recv.c msgr-common.c) add_executable(msgr-send msgr-send.c msgr-common.c) add_executable(reactor-recv reactor-recv.c msgr-common.c) add_executable(reactor-send reactor-send.c msgr-common.c) target_link_libraries(msgr-recv qpid-proton) target_link_libraries(msgr-send qpid-proton) target_link_libraries(reactor-recv qpid-proton) target_link_libraries(reactor-send qpid-proton) set_target_properties ( msgr-recv msgr-send reactor-recv reactor-send PROPERTIES COMPILE_FLAGS "${COMPILE_WARNING_FLAGS} ${COMPILE_LANGUAGE_FLAGS}" COMPILE_DEFINITIONS "${PLATFORM_DEFINITIONS}" ) if (BUILD_WITH_CXX) set_source_files_properties (msgr-recv.c msgr-send.c msgr-common.c reactor-recv.c reactor-send.c PROPERTIES LANGUAGE CXX) endif (BUILD_WITH_CXX) qpid-proton-0.14.0/tests/tools/apps/c/reactor-send.c0000644000175000017500000003227512770711161021557 0ustar danieldaniel/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ /* * Implements a subset of msgr-send.c using reactor events. */ #include "proton/message.h" #include "proton/error.h" #include "proton/types.h" #include "proton/reactor.h" #include "proton/handlers.h" #include "proton/engine.h" #include "proton/url.h" #include "msgr-common.h" #include #include #include #include typedef struct { Addresses_t targets; uint64_t msg_count; uint32_t msg_size; // of body uint32_t send_batch; int outgoing_window; unsigned int report_interval; // in seconds //Addresses_t subscriptions; //Addresses_t reply_tos; int get_replies; int unique_message; // 1 -> create and free a pn_message_t for each send/recv int timeout; // in seconds int incoming_window; int recv_count; const char *name; char *certificate; char *privatekey; // used to sign certificate char *password; // for private key file char *ca_db; // trusted CA database } Options_t; static void usage(int rc) { printf("Usage: reactor-send [OPTIONS] \n" " -a \tThe target address [amqp[s]://domain[/name]]\n" " -c # \tNumber of messages to send before exiting [0=forever]\n" " -b # \tSize of message body in bytes [1024]\n" " -R \tWait for a reply to each sent message\n" " -V \tEnable debug logging\n" ); exit(rc); } typedef struct { Options_t *opts; Statistics_t *stats; uint64_t sent; uint64_t received; pn_message_t *message; pn_message_t *reply_message; pn_atom_t id; char *encoded_data; size_t encoded_data_size; pn_url_t *send_url; pn_string_t *hostname; pn_string_t *container_id; pn_string_t *reply_to; } sender_context_t; void sender_context_init(sender_context_t *sc, Options_t *opts, Statistics_t *stats) { sc->opts = opts; sc->stats = stats; sc->sent = 0; sc->received = 0; sc->id.type = PN_ULONG; // 4096 extra bytes should easily cover the message metadata sc->encoded_data_size = sc->opts->msg_size + 4096; sc->encoded_data = (char *)calloc(1, sc->encoded_data_size); check(sc->encoded_data, "failed to allocate encoding buffer"); sc->container_id = pn_string("reactor-send"); // prefer uuid-like name sc->reply_message = (sc->opts->get_replies) ? pn_message() : 0; sc->message = pn_message(); check(sc->message, "failed to allocate a message"); sc->reply_to = pn_string("amqp://"); pn_string_addf(sc->reply_to, "%s", pn_string_get(sc->container_id)); pn_message_set_reply_to(sc->message, pn_string_get(sc->reply_to)); pn_data_t *body = pn_message_body(sc->message); // borrow the encoding buffer this one time char *data = sc->encoded_data; pn_data_put_binary(body, pn_bytes(sc->opts->msg_size, data)); check(sc->opts->targets.count > 0, "no specified address"); sc->send_url = pn_url_parse(sc->opts->targets.addresses[0]); const char *host = pn_url_get_host(sc->send_url); const char *port = pn_url_get_port(sc->send_url); sc->hostname = pn_string(host); if (port && strlen(port)) pn_string_addf(sc->hostname, ":%s", port); } sender_context_t *sender_context(pn_handler_t *h) { return (sender_context_t *) pn_handler_mem(h); } void sender_cleanup(pn_handler_t *h) { sender_context_t *sc = sender_context(h); pn_message_free(sc->message); pn_message_free(sc->reply_message); pn_url_free(sc->send_url); pn_free(sc->hostname); pn_free(sc->container_id); pn_free(sc->reply_to); free(sc->encoded_data); } pn_handler_t *replyto_handler(sender_context_t *sc); pn_message_t* get_message(sender_context_t *sc, bool sending) { if (sc->opts->unique_message) { pn_message_t *m = pn_message(); check(m, "failed to allocate a message"); if (sending) { pn_message_set_reply_to(m, pn_string_get(sc->reply_to)); // copy the data pn_data_t *body = pn_message_body(m); pn_data_t *template_body = pn_message_body(sc->message); pn_data_put_binary(body, pn_data_get_binary(template_body)); } return m; } else return sending ? sc->message : sc->reply_message; // our simplified "message pool" } void return_message(sender_context_t *sc, pn_message_t *m) { if (sc->opts->unique_message) pn_message_free(m); } void sender_dispatch(pn_handler_t *h, pn_event_t *event, pn_event_type_t type) { sender_context_t *sc = sender_context(h); switch (type) { case PN_CONNECTION_INIT: { pn_connection_t *conn = pn_event_connection(event); pn_connection_set_container(conn, pn_string_get(sc->container_id)); pn_connection_set_hostname(conn, pn_string_get(sc->hostname)); pn_connection_open(conn); pn_session_t *ssn = pn_session(conn); pn_session_open(ssn); pn_link_t *snd = pn_sender(ssn, "sender"); const char *path = pn_url_get_path(sc->send_url); if (path && strlen(path)) { pn_terminus_set_address(pn_link_target(snd), path); pn_terminus_set_address(pn_link_source(snd), path); } pn_link_open(snd); } break; case PN_LINK_FLOW: { pn_link_t *snd = pn_event_link(event); while (pn_link_credit(snd) > 0 && sc->sent < sc->opts->msg_count) { if (sc->sent == 0) statistics_start(sc->stats); char tag[8]; void *ptr = &tag; *((uint64_t *) ptr) = sc->sent; pn_delivery_t *dlv = pn_delivery(snd, pn_dtag(tag, 8)); // setup the message to send pn_message_t *msg = get_message(sc, true);; pn_message_set_address(msg, sc->opts->targets.addresses[0]); sc->id.u.as_ulong = sc->sent; pn_message_set_correlation_id(msg, sc->id); pn_message_set_creation_time(msg, msgr_now()); size_t size = sc->encoded_data_size; int err = pn_message_encode(msg, sc->encoded_data, &size); check(err == 0, "message encoding error"); pn_link_send(snd, sc->encoded_data, size); pn_delivery_settle(dlv); sc->sent++; return_message(sc, msg); } if (sc->sent == sc->opts->msg_count && !sc->opts->get_replies) { pn_link_close(snd); pn_connection_t *conn = pn_event_connection(event); pn_connection_close(conn); } } break; case PN_LINK_INIT: { pn_link_t *link = pn_event_link(event); if (pn_link_is_receiver(link)) { // Response messages link. Could manage credit and deliveries in this handler but // a dedicated handler also works. pn_handler_t *replyto = replyto_handler(sc); pn_flowcontroller_t *fc = pn_flowcontroller(1024); pn_handler_add(replyto, fc); pn_decref(fc); pn_handshaker_t *handshaker = pn_handshaker(); pn_handler_add(replyto, handshaker); pn_decref(handshaker); pn_record_t *record = pn_link_attachments(link); pn_record_set_handler(record, replyto); pn_decref(replyto); } } break; case PN_CONNECTION_LOCAL_CLOSE: { statistics_report(sc->stats, sc->sent, sc->received); } break; default: break; } } pn_handler_t *sender_handler(Options_t *opts, Statistics_t *stats) { pn_handler_t *h = pn_handler_new(sender_dispatch, sizeof(sender_context_t), sender_cleanup); sender_context_t *sc = sender_context(h); sender_context_init(sc, opts, stats); return h; } sender_context_t *replyto_sender_context(pn_handler_t *h) { sender_context_t **p = (sender_context_t **) pn_handler_mem(h); return *p; } void replyto_cleanup(pn_handler_t *h) {} void replyto_dispatch(pn_handler_t *h, pn_event_t *event, pn_event_type_t type) { sender_context_t *sc = replyto_sender_context(h); switch (type) { case PN_DELIVERY: { check(sc->opts->get_replies, "Unexpected reply message"); pn_link_t *recv_link = pn_event_link(event); pn_delivery_t *dlv = pn_event_delivery(event); if (pn_link_is_receiver(recv_link) && !pn_delivery_partial(dlv)) { size_t encoded_size = pn_delivery_pending(dlv); check(encoded_size <= sc->encoded_data_size, "decoding buffer too small"); ssize_t n = pn_link_recv(recv_link, sc->encoded_data, encoded_size); check(n == (ssize_t)encoded_size, "read fail on reply link"); pn_message_t *msg = get_message(sc, false); int err = pn_message_decode(msg, sc->encoded_data, n); check(err == 0, "message decode error"); statistics_msg_received(sc->stats, msg); sc->received++; pn_delivery_settle(dlv); return_message(sc, msg); } if (sc->received == sc->opts->msg_count) { pn_link_close(recv_link); pn_connection_t *conn = pn_event_connection(event); pn_connection_close(conn); } } break; default: break; } } pn_handler_t *replyto_handler(sender_context_t *sc) { pn_handler_t *h = pn_handler_new(replyto_dispatch, sizeof(sender_context_t *), replyto_cleanup); sender_context_t **p = (sender_context_t **) pn_handler_mem(h); *p = sc; return h; } static void parse_options( int argc, char **argv, Options_t *opts ) { int c; opterr = 0; memset( opts, 0, sizeof(*opts) ); opts->msg_size = 1024; opts->send_batch = 1024; opts->timeout = -1; opts->recv_count = -1; opts->unique_message = 0; addresses_init(&opts->targets); while ((c = getopt(argc, argv, "ua:c:b:p:w:e:l:Rt:W:B:VN:T:C:K:P:")) != -1) { switch(c) { case 'a': { // TODO: multiple addresses? To keep tests happy, accept multiple for now, // but ignore all but the first. addresses_merge( &opts->targets, optarg ); } break; case 'c': if (sscanf( optarg, "%" SCNu64, &opts->msg_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'b': if (sscanf( optarg, "%u", &opts->msg_size ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'p': if (sscanf( optarg, "%u", &opts->send_batch ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'w': if (sscanf( optarg, "%d", &opts->outgoing_window ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'e': if (sscanf( optarg, "%u", &opts->report_interval ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'R': opts->get_replies = 1; break; case 'u': opts->unique_message = 1; break; case 't': if (sscanf( optarg, "%d", &opts->timeout ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } if (opts->timeout > 0) opts->timeout *= 1000; break; case 'W': if (sscanf( optarg, "%d", &opts->incoming_window ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'B': if (sscanf( optarg, "%d", &opts->recv_count ) != 1) { fprintf(stderr, "Option -%c requires an integer argument.\n", optopt); usage(1); } break; case 'V': enable_logging(); break; case 'N': opts->name = optarg; break; case 'T': opts->ca_db = optarg; break; case 'C': opts->certificate = optarg; break; case 'K': opts->privatekey = optarg; break; case 'P': parse_password( optarg, &opts->password ); break; default: usage(1); } } // default target if none specified if (opts->targets.count == 0) addresses_add( &opts->targets, "amqp://0.0.0.0" ); } int main(int argc, char** argv) { Options_t opts; Statistics_t stats; parse_options( argc, argv, &opts ); pn_reactor_t *reactor = pn_reactor(); pn_handler_t *sh = sender_handler(&opts, &stats); pn_handler_add(sh, pn_handshaker()); pn_reactor_connection(reactor, sh); pn_reactor_run(reactor); pn_reactor_free(reactor); pn_handler_free(sh); addresses_free(&opts.targets); return 0; } qpid-proton-0.14.0/tests/tools/apps/python/0000755000175000017500000000000012770711161020113 5ustar danieldanielqpid-proton-0.14.0/tests/tools/apps/python/msgr-recv.py0000755000175000017500000001577312770711161022412 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse, time import logging from proton import * # Hi python3! try: long() except: long = int usage = """ Usage: msgr-recv [OPTIONS] -a [,]* \tAddresses to listen on [amqp://~0.0.0.0] -c # \tNumber of messages to receive before exiting [0=forever] -b # \tArgument to Messenger::recv(n) [2048] -w # \tSize for incoming window [0] -t # \tInactivity timeout in seconds, -1 = no timeout [-1] -e # \t# seconds to report statistics, 0 = end of test [0] *TBD* -R \tSend reply if 'reply-to' present -W # \t# outgoing window size [0] -F [,]* \tAddresses used for forwarding received messages -N \tSet the container name to -X \tPrint '\\n' to stdout after all subscriptions are created -V \tEnable debug logging""" def parse_options( argv ): parser = optparse.OptionParser(usage=usage) parser.add_option("-a", dest="subscriptions", action="append", type="string") parser.add_option("-c", dest="msg_count", type="int", default=0) parser.add_option("-b", dest="recv_count", type="int", default=-1) parser.add_option("-w", dest="incoming_window", type="int") parser.add_option("-t", dest="timeout", type="int", default=-1) parser.add_option("-e", dest="report_interval", type="int", default=0) parser.add_option("-R", dest="reply", action="store_true") parser.add_option("-W", dest="outgoing_window", type="int") parser.add_option("-F", dest="forwarding_targets", action="append", type="string") parser.add_option("-N", dest="name", type="string") parser.add_option("-X", dest="ready_text", type="string") parser.add_option("-V", dest="verbose", action="store_true") return parser.parse_args(args=argv) class Statistics(object): def __init__(self): self.start_time = 0.0 self.latency_samples = 0 self.latency_total = 0.0 self.latency_min = None self.latency_max = None def start(self): self.start_time = time.time() def msg_received(self, msg): ts = msg.creation_time if ts: l = long(time.time() * 1000) - ts if l > 0.0: self.latency_total += l self.latency_samples += 1 if self.latency_samples == 1: self.latency_min = self.latency_max = l else: if self.latency_min > l: self.latency_min = l if self.latency_max < l: self.latency_max = l def report(self, sent, received): secs = time.time() - self.start_time print("Messages sent: %d recv: %d" % (sent, received) ) print("Total time: %f sec" % secs ) if secs: print("Throughput: %f msgs/sec" % (sent/secs) ) if self.latency_samples: print("Latency (sec): %f min %f max %f avg" % (self.latency_min/1000.0, self.latency_max/1000.0, (self.latency_total/self.latency_samples)/1000.0)) def main(argv=None): opts = parse_options(argv)[0] if opts.subscriptions is None: opts.subscriptions = ["amqp://~0.0.0.0"] stats = Statistics() sent = 0 received = 0 forwarding_index = 0 log = logging.getLogger("msgr-recv") log.addHandler(logging.StreamHandler()) if opts.verbose: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) message = Message() messenger = Messenger( opts.name ) if opts.incoming_window is not None: messenger.incoming_window = opts.incoming_window if opts.timeout > 0: opts.timeout *= 1000 messenger.timeout = opts.timeout messenger.start() # unpack addresses that were specified using comma-separated list for x in opts.subscriptions: z = x.split(",") for y in z: if y: log.debug("Subscribing to %s", y) messenger.subscribe(y) forwarding_targets = [] if opts.forwarding_targets: for x in opts.forwarding_targets: z = x.split(",") for y in z: if y: forwarding_targets.append(y) # hack to let test scripts know when the receivers are ready (so that the # senders may be started) if opts.ready_text: print("%s" % opts.ready_text) sys.stdout.flush() while opts.msg_count == 0 or received < opts.msg_count: log.debug("Calling pn_messenger_recv(%d)", opts.recv_count) rc = messenger.recv(opts.recv_count) # start the timer only after receiving the first msg if received == 0: stats.start() log.debug("Messages on incoming queue: %d", messenger.incoming) while messenger.incoming > 0: messenger.get(message) received += 1 # TODO: header decoding? # uint64_t id = pn_message_get_correlation_id( message ).u.as_ulong; stats.msg_received( message ) if opts.reply: if message.reply_to: log.debug("Replying to: %s", message.reply_to ) message.address = message.reply_to message.creation_time = long(time.time() * 1000) messenger.put( message ) sent += 1 if forwarding_targets: forward_addr = forwarding_targets[forwarding_index] forwarding_index += 1 if forwarding_index == len(forwarding_targets): forwarding_index = 0 log.debug("Forwarding to: %s", forward_addr ) message.address = forward_addr message.reply_to = None message.creation_time = long(time.time() * 1000) messenger.put( message ) sent += 1 log.debug("Messages received=%lu sent=%lu", received, sent) # this will flush any pending sends if messenger.outgoing > 0: log.debug("Calling pn_messenger_send()") messenger.send() messenger.stop() stats.report( sent, received ) return 0 if __name__ == "__main__": sys.exit(main()) qpid-proton-0.14.0/tests/tools/apps/python/msgr-send.py0000755000175000017500000001554412770711161022400 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse, time import logging from proton import * # Hi python3! try: long() except: long = int usage = """ Usage: msgr-send [OPTIONS] -a [,]* \tThe target address [amqp[s]://domain[/name]] -c # \tNumber of messages to send before exiting [0=forever] -b # \tSize of message body in bytes [1024] -p # \tSend batches of # messages (wait for replies before sending next batch if -R) [1024] -w # \t# outgoing window size [0] -e # \t# seconds to report statistics, 0 = end of test [0] -R \tWait for a reply to each sent message -t # \tInactivity timeout in seconds, -1 = no timeout [-1] -W # \tIncoming window size [0] -B # \tArgument to Messenger::recv(n) [-1] -N \tSet the container name to -V \tEnable debug logging""" def parse_options( argv ): parser = optparse.OptionParser(usage=usage) parser.add_option("-a", dest="targets", action="append", type="string") parser.add_option("-c", dest="msg_count", type="int", default=0) parser.add_option("-b", dest="msg_size", type="int", default=1024) parser.add_option("-p", dest="send_batch", type="int", default=1024) parser.add_option("-w", dest="outgoing_window", type="int") parser.add_option("-e", dest="report_interval", type="int", default=0) parser.add_option("-R", dest="get_replies", action="store_true") parser.add_option("-t", dest="timeout", type="int", default=-1) parser.add_option("-W", dest="incoming_window", type="int") parser.add_option("-B", dest="recv_count", type="int", default=-1) parser.add_option("-N", dest="name", type="string") parser.add_option("-V", dest="verbose", action="store_true") return parser.parse_args(args=argv) class Statistics(object): def __init__(self): self.start_time = 0.0 self.latency_samples = 0 self.latency_total = 0.0 self.latency_min = None self.latency_max = None def start(self): self.start_time = time.time() def msg_received(self, msg): ts = msg.creation_time if ts: l = long(time.time() * 1000) - ts if l > 0.0: self.latency_total += l self.latency_samples += 1 if self.latency_samples == 1: self.latency_min = self.latency_max = l else: if self.latency_min > l: self.latency_min = l if self.latency_max < l: self.latency_max = l def report(self, sent, received): secs = time.time() - self.start_time print("Messages sent: %d recv: %d" % (sent, received) ) print("Total time: %f sec" % secs ) if secs: print("Throughput: %f msgs/sec" % (sent/secs) ) if self.latency_samples: print("Latency (sec): %f min %f max %f avg" % (self.latency_min/1000.0, self.latency_max/1000.0, (self.latency_total/self.latency_samples)/1000.0)) def process_replies( messenger, message, stats, max_count, log): """ Return the # of reply messages received """ received = 0 log.debug("Calling pn_messenger_recv(%d)", max_count) messenger.recv( max_count ) log.debug("Messages on incoming queue: %d", messenger.incoming) while messenger.incoming > 0: messenger.get( message ) received += 1 # TODO: header decoding? stats.msg_received( message ) # uint64_t id = pn_message_get_correlation_id( message ).u.as_ulong; return received def main(argv=None): opts = parse_options(argv)[0] if opts.targets is None: opts.targets = ["amqp://0.0.0.0"] stats = Statistics() sent = 0 received = 0 target_index = 0 log = logging.getLogger("msgr-send") log.addHandler(logging.StreamHandler()) if opts.verbose: log.setLevel(logging.DEBUG) else: log.setLevel(logging.INFO) message = Message() message.reply_to = "~" message.body = "X" * opts.msg_size reply_message = Message() messenger = Messenger( opts.name ) if opts.outgoing_window is not None: messenger.outgoing_window = opts.outgoing_window if opts.timeout > 0: opts.timeout *= 1000 messenger.timeout = opts.timeout messenger.start() # unpack targets that were specified using comma-separated list # targets = [] for x in opts.targets: z = x.split(",") for y in z: if y: targets.append(y) stats.start() while opts.msg_count == 0 or sent < opts.msg_count: # send a message message.address = targets[target_index] if target_index == len(targets) - 1: target_index = 0 else: target_index += 1 message.correlation_id = sent message.creation_time = long(time.time() * 1000) messenger.put( message ) sent += 1 if opts.send_batch and (messenger.outgoing >= opts.send_batch): if opts.get_replies: while received < sent: # this will also transmit any pending sent messages received += process_replies( messenger, reply_message, stats, opts.recv_count, log ) else: log.debug("Calling pn_messenger_send()") messenger.send() log.debug("Messages received=%d sent=%d", received, sent) if opts.get_replies: # wait for the last of the replies while received < sent: count = process_replies( messenger, reply_message, stats, opts.recv_count, log ) received += count log.debug("Messages received=%d sent=%d", received, sent) elif messenger.outgoing > 0: log.debug("Calling pn_messenger_send()") messenger.send() messenger.stop() stats.report( sent, received ) return 0 if __name__ == "__main__": sys.exit(main()) qpid-proton-0.14.0/tests/tools/apps/python/reactor-send.py0000644000175000017500000000624412770711161023061 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import optparse from proton import Message from proton.handlers import MessagingHandler from proton.reactor import Container class Send(MessagingHandler): def __init__(self, url, messages, size, replying): super(Send, self).__init__(prefetch=1024) self.url = url self.sent = 0 self.confirmed = 0 self.received = 0 self.received_bytes = 0 self.total = messages self.message_size = size; self.replying = replying; self.message = Message(body="X" * self.message_size) if replying: self.message.reply_to = "localhost/test" def on_start(self, event): event.container.sasl_enabled = False event.container.create_sender(self.url) def on_sendable(self, event): while event.sender.credit and self.sent < self.total: self.message.correlation_id = self.sent + 1 event.sender.send(self.message) self.sent += 1 def on_accepted(self, event): self.confirmed += 1 if self.confirmed == self.total: print("all messages confirmed") if not self.replying: event.connection.close() def on_message(self, event): msg = event.message; if self.received < self.total: self.received += 1 self.received_bytes += len(msg.body) if self.received == self.total: event.receiver.close() event.connection.close() def on_disconnected(self, event): self.sent = self.confirmed parser = optparse.OptionParser(usage="usage: %prog [options]", description="Send messages to the supplied address.") parser.add_option("-a", "--address", default="localhost:5672/examples", help="address to which messages are sent (default %default)") parser.add_option("-c", "--messages", type="int", default=100, help="number of messages to send (default %default)") parser.add_option("-b", "--bytes", type="int", default=100, help="size of each message body in bytes (default %default)") parser.add_option("-R", action="store_true", dest="replying", help="process reply messages") opts, args = parser.parse_args() try: Container(Send(opts.address, opts.messages, opts.bytes, opts.replying)).run() except KeyboardInterrupt: pass qpid-proton-0.14.0/tests/tools/apps/cpp/0000755000175000017500000000000012770711161017354 5ustar danieldanielqpid-proton-0.14.0/tests/tools/apps/cpp/CMakeLists.txt0000644000175000017500000000453212770711161022120 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # include_directories("${CMAKE_SOURCE_DIR}/examples/cpp" "${CMAKE_SOURCE_DIR}/examples/cpp/lib") add_executable(reactor_send_cpp reactor_send.cpp) target_link_libraries(reactor_send_cpp qpid-proton qpid-proton-cpp) if (CMAKE_SYSTEM_NAME STREQUAL Windows) # No change needed for windows already use correct separator function(to_native_path path result) file (TO_NATIVE_PATH "${path}" path) set (${result} ${path} PARENT_SCOPE) endfunction() else (CMAKE_SYSTEM_NAME STREQUAL Windows) # Just change ';'->':' function(to_native_path path result) file (TO_NATIVE_PATH "${path}" path) string (REGEX REPLACE ";" ":" path "${path}") set (${result} ${path} PARENT_SCOPE) endfunction() endif (CMAKE_SYSTEM_NAME STREQUAL Windows) set (py_bld "$" "$") # For windows set (app_path $ $) set (py_path ${py_bld} ${app_path} $ENV{PATH}) to_native_path("${py_path}" py_path) set (py_pythonpath "${CMAKE_SOURCE_DIR}/examples/cpp" $ENV{PYTHONPATH}) to_native_path ("${py_pythonpath}" py_pythonpath) set (perf_pythonpath "${py_pythonpath}" "${CMAKE_SOURCE_DIR}/examples/cpp") to_native_path ("${perf_pythonpath}" perf_pythonpath) add_custom_target(quick_perf_cpp ${PYTHON_EXECUTABLE} ${CMAKE_SOURCE_DIR}/proton-c/env.py -- "PATH=${py_path}" "PYTHONPATH=${perf_pythonpath}" ${PYTHON_EXECUTABLE} "${CMAKE_SOURCE_DIR}/tests/perf/quick_perf.py" "CPP") add_dependencies(quick_perf_cpp reactor_send_cpp reactor-recv qpid-proton-cpp) qpid-proton-0.14.0/tests/tools/apps/cpp/reactor_send.cpp0000644000175000017500000001017512770711161022534 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include "options.hpp" #include "proton/binary.hpp" #include "proton/connection.hpp" #include "proton/default_container.hpp" #include "proton/codec/decoder.hpp" #include "proton/delivery.hpp" #include "proton/messaging_handler.hpp" #include "proton/tracker.hpp" #include "proton/value.hpp" #include #include #include #include #include class reactor_send : public proton::messaging_handler { private: std::string url_; proton::message message_; std::string reply_to_; int sent_; int confirmed_; int total_; int received_; size_t received_bytes_; proton::binary received_content_; bool replying_; proton::message_id id_value_; public: reactor_send(const std::string &url, int c, int size, bool replying) : url_(url), sent_(0), confirmed_(0), total_(c), received_(0), received_bytes_(0), replying_(replying) { if (replying_) message_.reply_to("localhost/test"); proton::binary content; content.assign((size_t) size, 'X'); message_.body(content); } void on_container_start(proton::container &c) PN_CPP_OVERRIDE { c.receiver_options(proton::receiver_options().credit_window(1024)); c.open_sender(url_); } void on_sendable(proton::sender &sender) PN_CPP_OVERRIDE { while (sender.credit() && sent_ < total_) { id_value_ = sent_ + 1; message_.correlation_id(id_value_); message_.creation_time(proton::timestamp::now()); sender.send(message_); sent_++; } } void on_tracker_accept(proton::tracker &t) PN_CPP_OVERRIDE { confirmed_++; t.settle(); if (confirmed_ == total_) { std::cout << "all messages confirmed" << std::endl; if (!replying_) t.connection().close(); } } void on_message(proton::delivery &d, proton::message &msg) PN_CPP_OVERRIDE { received_content_ = proton::get(msg.body()); received_bytes_ += received_content_.size(); if (received_ < total_) { received_++; } d.settle(); if (received_ == total_) { d.receiver().close(); d.connection().close(); } } void on_transport_close(proton::transport &) PN_CPP_OVERRIDE { sent_ = confirmed_; } }; int main(int argc, char **argv) { // Command line options std::string address("127.0.0.1:5672/cpp_tests"); int message_count = 10; int message_size = 100; bool replying = false; example::options opts(argc, argv); opts.add_value(address, 'a', "address", "connect and send to URL", "URL"); opts.add_value(message_count, 'c', "messages", "send COUNT messages", "COUNT"); opts.add_value(message_size, 'b', "bytes", "send binary messages BYTES long", "BYTES"); opts.add_value(replying, 'R', "replying", "process reply messages", "REPLYING"); try { opts.parse(); reactor_send send(address, message_count, message_size, replying); proton::default_container(send).run(); return 0; } catch (const example::bad_option& e) { std::cout << opts << std::endl << e.what() << std::endl; } catch (const std::exception& e) { std::cerr << e.what() << std::endl; } return 1; } qpid-proton-0.14.0/tests/tools/soak-check0000755000175000017500000001130512770711161017565 0ustar danieldaniel#!/usr/bin/env python # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT 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 __future__ import print_function import sys, optparse from subprocess import Popen,PIPE def run_test(cmd): try: process = Popen(cmd) except OSError: assert False, "Unable to execute command '%s', is it in your PATH?" % cmd[0] return process.wait() def main(argv=None): """ Run a subset of the Proton tests for an extended period of time. """ # tests is a list of test configurations. Each configuration is # represented as a two-element tuple. Tuple[0] is the pattern passed to # proton-test that identifies the test case. Tuple[1] is a list of maps. # Each map contains the parameters for one test. A test (of 'pattern') is # executed for each map in Tuple[1] parser = optparse.OptionParser() parser.add_option("-i", "--iterations", action="store", type="int", default=1, help="# of times to repeat each test.") parser.add_option("-v", "--verbose", action="store_true", help="print extra detail to stdout") opts, extra = parser.parse_args(args=argv) iterations = opts.iterations verbose = opts.verbose tests = [ ("proton_tests.soak.MessengerTests.test_oneway_*", # 104,297 * 7 = 730,079 msgs transferred per iteration [{ "iterations": iterations, "send_count": 104297, "target_count": 7 }]), ("proton_tests.soak.MessengerTests.test_echo_*", # 102,811 * 5 * 2 (send+reply) = 1,028,110 msgs transferred per iteration [{"iterations": iterations, "send_count": 102811, "target_count": 5, "send_batch": 3187}]), ("proton_tests.soak.MessengerTests.test_relay_*", # 102,197 * 4 * 3 (send+reply+forward)= 1,226,364 msgs transferred per iteration [{"iterations": iterations, "send_count": 102197, "target_count": 4, "send_batch": 829, "forward_count": 7}]), ("proton_tests.soak.MessengerTests.test_star_topology_*", # 2 ports * 3 senders = 6 connections per iteration # 6 connections * 7 targets = 42 links per iteration # 42 links * 35419 msg * 2 (send/reply) = 2,975,196 msgs per iteration [{"iterations": iterations, "port_count": 2, "sender_count": 3, "target_count": 7, "send_count": 35419, "send_batch": 311}]), # # Scale up the number of connections and links # ("proton_tests.soak.MessengerTests.test_star_topology_C", # 10 ports * 10 senders = 100 connections per iteration # 100 connections * 11 targets = 1100 links per iteration # 1100 links * 311 msg * 2 (send/reply) = 684,200 msgs per iteration [{"iterations": iterations, "port_count": 10, "sender_count": 10, "target_count": 11, "send_count": 311, "send_batch": 3}]), ("proton_tests.soak.MessengerTests.test_star_topology_C_SSL", # 10 ports * 10 senders = 100 connections per iteration # 100 connections * 11 targets = 1100 links per iteration # 1100 links * 30 msg * 2 (send/reply) = 66000 msgs per iteration [{"iterations": iterations, "port_count": 10, "sender_count": 10, "target_count": 11, "send_count": 30, "send_batch": 3}]) ] for test in tests: pattern = test[0] param_list = test[1] for test_params in param_list: command = ["proton-test"] for (k, v) in test_params.iteritems(): command.append( "-D%s=%s" % (k,v) ) if verbose: command.append( "-Dverbose" ) command.append( pattern ) if verbose: print("command='%s'" % str(command)) run_test(command) return 0 if __name__ == "__main__": sys.exit(main()) qpid-proton-0.14.0/tests/perf/0000755000175000017500000000000012770711161015423 5ustar danieldanielqpid-proton-0.14.0/tests/perf/README.txt0000644000175000017500000000107312770711161017122 0ustar danieldanielSimple performance tests. quick_perf coordinates two processes: a simple fast echo "server" and a client that sends and receives simple binary messages over a single connection on the loopback interface. The latter is timed. This provides a crude view of the overhead of the Proton library alone (CMake target "quick_perf_c") or with a language binding. It is most useful for verifying a lack of performance degradation on a large ckeckin or between releases. It probably says little about expected performance on a physical network or for a particular application. qpid-proton-0.14.0/tests/perf/quick_perf.py0000644000175000017500000000515612770711161020134 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License # # For use with CMake to run simple performance tests in Proton. # Assumes that rector-recv and reactor-send can be found in PATH. # CMkake's choice of python executable may be passed via PYTHON_EXE environment var. # Add any OS specific monitor helpers in PN_QPERF_MON: i.e. # PN_QPERF_MON="time taskset 0x2" make quick_perf_c import os, sys, socket, time from example_test import Proc, pick_addr from subprocess import Popen, PIPE, STDOUT NULL = open(os.devnull, 'w') connaddr = pick_addr() linkaddr = connaddr + "/perf_test" if 'PYTHON_EXE' in os.environ: python_exe = os.environ['PYTHON_EXE'] else: python_exe = 'python' if 'PN_QPERF_MON' in os.environ: monitor_cmd = os.environ['PN_QPERF_MON'].split() else: monitor_cmd = [] mcount = 5000000 if 'PYTHON' in sys.argv: mcount /= 10 perf_targets = {'C' : ['reactor-send', "-a", linkaddr, "-c", str(mcount), "-R"], 'CPP' : ['reactor_send_cpp', "-a", linkaddr, "-c", str(mcount), "-R", "1"], 'PYTHON' : [python_exe, 'reactor-send.py', "-a", linkaddr, "-c", str(mcount), "-R"] } try: perf_target = monitor_cmd + perf_targets[sys.argv[1]] except: print "Usage: python quick_perf [C|CPP|PYTHON]" raise # Use Proton-C reactor-recv as a relatively fast loopback "broker" for these tests server = Proc(["reactor-recv", "-X", "listening", "-a", linkaddr, "-c", str(mcount), "-R"], ready="listening", skip_valgrind=True, timeout=300) try: start = time.time() client = Proc(perf_target, skip_valgrind=True, timeout=300) print client.wait_exit() server.wait_exit() end = time.time() except Exception as e: if server: server.safe_kill() raise Exception("Error running %s: %s", server, e) secs = end - start print("%d loopback messages in %.1f secs" % (mcount * 2, secs) ) print("%.0f msgs/sec" % (mcount * 2 / secs) ) qpid-proton-0.14.0/tests/pom.xml0000644000175000017500000001000212770711161015775 0ustar danieldaniel 4.0.0 proton-tests proton-tests org.apache.qpid proton-project 0.14.0 The Proton python system tests execute against the Java or C implementation, using Maven (via this pom) and CMake/CTest respectively. To run the tests against proton-j, execute: mvn test Example of advanced usage (all of the -D flags are optional): mvn test \ -Dproton.pythontest.pattern='proton_tests.transport.ClientTransportTest.*' \ -Dproton.pythontest.invocations=20 \ -Dproton.pythontest.always_colorize=true http://svn.apache.org/viewvc/qpid/proton/ ${basedir}/target/surefire-reports java resources org.apache.maven.plugins maven-surefire-plugin ${basedir}/java/pythonTests.ignore ${basedir}/python ${basedir}/../proton-c/bindings/python ${basedir}/java/shim ${basedir}/python/proton-test ${testReportOutputDirectory} ${project.build.outputDirectory}/logging.properties ${testReportOutputDirectory} org.apache.maven.plugins maven-jar-plugin 2.6 test-jar org.apache.qpid proton-j ${project.parent.version} org.bouncycastle bcpkix-jdk15on 1.47 org.python jython-standalone 2.7.0 test qpid-proton-0.14.0/tools/0000755000175000017500000000000012770711161014465 5ustar danieldanielqpid-proton-0.14.0/tools/cmake/0000755000175000017500000000000012770711161015545 5ustar danieldanielqpid-proton-0.14.0/tools/cmake/Modules/0000755000175000017500000000000012770711161017155 5ustar danieldanielqpid-proton-0.14.0/tools/cmake/Modules/FindEmscripten.cmake0000644000175000017500000000327612770711161023101 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # FindEmscripten # This module checks if Emscripten and its prerequisites are installed and if so # sets EMSCRIPTEN_FOUND Emscripten (https://github.com/kripken/emscripten) is a # C/C++ to JavaScript cross-compiler used to generate the JavaScript bindings. if (NOT EMSCRIPTEN_FOUND) # First check that Node.js is installed as that is needed by Emscripten. find_program(NODE node) if (NOT NODE) message(STATUS "Node.js (http://nodejs.org) is not installed: can't build JavaScript binding") else (NOT NODE) # Check that the Emscripten C/C++ to JavaScript cross-compiler is installed. find_program(EMCC emcc) if (NOT EMCC) message(STATUS "Emscripten (https://github.com/kripken/emscripten) is not installed: can't build JavaScript binding") else (NOT EMCC) set(EMSCRIPTEN_FOUND ON) endif (NOT EMCC) endif (NOT NODE) endif (NOT EMSCRIPTEN_FOUND) qpid-proton-0.14.0/tools/cmake/Modules/FindJava.cmake0000644000175000017500000001776712770711161021663 0ustar danieldaniel# - Find Java # This module finds if Java is installed and determines where the # include files and libraries are. This code sets the following # variables: # # Java_JAVA_EXECUTABLE = the full path to the Java runtime # Java_JAVAC_EXECUTABLE = the full path to the Java compiler # Java_JAVAH_EXECUTABLE = the full path to the Java header generator # Java_JAVADOC_EXECUTABLE = the full path to the Java documention generator # Java_JAR_EXECUTABLE = the full path to the Java archiver # Java_VERSION_STRING = Version of the package found (java version), eg. 1.6.0_12 # Java_VERSION_MAJOR = The major version of the package found. # Java_VERSION_MINOR = The minor version of the package found. # Java_VERSION_PATCH = The patch version of the package found. # Java_VERSION_TWEAK = The tweak version of the package found (after '_') # Java_VERSION = This is set to: $major.$minor.$patch(.$tweak) # # The minimum required version of Java can be specified using the # standard CMake syntax, e.g. find_package(Java 1.5) # # NOTE: ${Java_VERSION} and ${Java_VERSION_STRING} are not guaranteed to be # identical. For example some java version may return: # Java_VERSION_STRING = 1.5.0_17 # and # Java_VERSION = 1.5.0.17 # # another example is the Java OEM, with: # Java_VERSION_STRING = 1.6.0-oem # and # Java_VERSION = 1.6.0 # # For these components the following variables are set: # # Java_FOUND - TRUE if all components are found. # Java_INCLUDE_DIRS - Full paths to all include dirs. # Java_LIBRARIES - Full paths to all libraries. # Java__FOUND - TRUE if is found. # # Example Usages: # find_package(Java) # find_package(Java COMPONENTS Runtime) # find_package(Java COMPONENTS Development) # #============================================================================= # Copyright 2002-2009 Kitware, Inc. # Copyright 2009-2011 Mathieu Malaterre # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) # The HINTS option should only be used for values computed from the system. set(_JAVA_HINTS "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\2.0;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.9;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.8;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.7;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.6;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.5;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.4;JavaHome]/bin" "[HKEY_LOCAL_MACHINE\\SOFTWARE\\JavaSoft\\Java Development Kit\\1.3;JavaHome]/bin" $ENV{JAVA_HOME}/bin ) # Hard-coded guesses should still go in PATHS. This ensures that the user # environment can always override hard guesses. set(_JAVA_PATHS /usr/lib/java/bin /usr/share/java/bin /usr/local/java/bin /usr/local/java/share/bin /usr/java/j2sdk1.4.2_04 /usr/lib/j2sdk1.4-sun/bin /usr/java/j2sdk1.4.2_09/bin /usr/lib/j2sdk1.5-sun/bin /opt/sun-jdk-1.5.0.04/bin ) find_program(Java_JAVA_EXECUTABLE NAMES java HINTS ${_JAVA_HINTS} PATHS ${_JAVA_PATHS} ) if(Java_JAVA_EXECUTABLE) execute_process(COMMAND ${Java_JAVA_EXECUTABLE} -version RESULT_VARIABLE res OUTPUT_VARIABLE var ERROR_VARIABLE var # sun-java output to stderr OUTPUT_STRIP_TRAILING_WHITESPACE ERROR_STRIP_TRAILING_WHITESPACE) if( res ) if(${Java_FIND_REQUIRED}) message( FATAL_ERROR "Error executing java -version" ) else() message( STATUS "Warning, could not run java --version") endif() else() # extract major/minor version and patch level from "java -version" output # Tested on linux using # 1. Sun / Sun OEM # 2. OpenJDK 1.6 # 3. GCJ 1.5 # 4. Kaffe 1.4.2 if(var MATCHES "(java|openjdk) version \"[0-9]+\\.[0-9]+\\.[0-9_.]+.*\".*") # This is most likely Sun / OpenJDK, or maybe GCJ-java compat layer string( REGEX REPLACE ".* version \"([0-9]+\\.[0-9]+\\.[0-9_.]+.*)\".*" "\\1" Java_VERSION_STRING "${var}" ) elseif(var MATCHES "java full version \"kaffe-[0-9]+\\.[0-9]+\\.[0-9_]+\".*") # Kaffe style string( REGEX REPLACE "java full version \"kaffe-([0-9]+\\.[0-9]+\\.[0-9_]+).*" "\\1" Java_VERSION_STRING "${var}" ) else() if(NOT Java_FIND_QUIETLY) message(WARNING "regex not supported: ${var}. Please report") endif() endif() string( REGEX REPLACE "([0-9]+).*" "\\1" Java_VERSION_MAJOR "${Java_VERSION_STRING}" ) string( REGEX REPLACE "[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_MINOR "${Java_VERSION_STRING}" ) string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.([0-9]+).*" "\\1" Java_VERSION_PATCH "${Java_VERSION_STRING}" ) # warning tweak version can be empty: string( REGEX REPLACE "[0-9]+\\.[0-9]+\\.[0-9]+[_\\.]?([0-9]*).*$" "\\1" Java_VERSION_TWEAK "${Java_VERSION_STRING}" ) if( Java_VERSION_TWEAK STREQUAL "" ) # check case where tweak is not defined set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}) else() set(Java_VERSION ${Java_VERSION_MAJOR}.${Java_VERSION_MINOR}.${Java_VERSION_PATCH}.${Java_VERSION_TWEAK}) endif() endif() endif() find_program(Java_JAR_EXECUTABLE NAMES jar HINTS ${_JAVA_HINTS} PATHS ${_JAVA_PATHS} ) find_program(Java_JAVAC_EXECUTABLE NAMES javac HINTS ${_JAVA_HINTS} PATHS ${_JAVA_PATHS} ) find_program(Java_JAVAH_EXECUTABLE NAMES javah HINTS ${_JAVA_HINTS} PATHS ${_JAVA_PATHS} ) find_program(Java_JAVADOC_EXECUTABLE NAMES javadoc HINTS ${_JAVA_HINTS} PATHS ${_JAVA_PATHS} ) #include(${CMAKE_CURRENT_LIST_DIR}/FindPackageHandleStandardArgs.cmake) include(FindPackageHandleStandardArgs) if(Java_FIND_COMPONENTS) # Apache Qpid Proton doesn't support this because of find_package_handle_standard_args # differences (see comment below) message(FATAL_ERROR "Apache Qpid Proton FindJava does not support Java_FIND_COMPONENTS") foreach(component ${Java_FIND_COMPONENTS}) # User just want to execute some Java byte-compiled if(component STREQUAL "Runtime") find_package_handle_standard_args(Java REQUIRED_VARS Java_JAVA_EXECUTABLE VERSION_VAR Java_VERSION ) elseif(component STREQUAL "Development") find_package_handle_standard_args(Java REQUIRED_VARS Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE VERSION_VAR Java_VERSION ) else() message(FATAL_ERROR "Comp: ${component} is not handled") endif() set(Java_${component}_FOUND TRUE) endforeach() else() # Check for everything # Apache Qpid Proton local change: the line below has been tweaked because # the signature of find_package_handle_standard_args in cmake 2.6 lacks the # REQUIRED_VARS and VERSION_VAR parameters, and specifies the error message differently. find_package_handle_standard_args(Java DEFAULT_MSG Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE ) endif() mark_as_advanced( Java_JAVA_EXECUTABLE Java_JAR_EXECUTABLE Java_JAVAC_EXECUTABLE Java_JAVAH_EXECUTABLE Java_JAVADOC_EXECUTABLE ) # LEGACY set(JAVA_RUNTIME ${Java_JAVA_EXECUTABLE}) set(JAVA_ARCHIVE ${Java_JAR_EXECUTABLE}) set(JAVA_COMPILE ${Java_JAVAC_EXECUTABLE}) qpid-proton-0.14.0/tools/cmake/Modules/FindNodePackages.cmake0000644000175000017500000000545612770711161023316 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # FindNodePackages # This module finds and installs (using npm) node.js packages that are used by # the JavaScript binding. The binding should still compile if these packages # cannot be installed but certain features might not work as described below. # # * The ws package is the WebSocket library used by emscripten when the target is # node.js, it isn't needed for applications hosted on a browser (where native # WebSockets will be used), but without it it won't work with node.js. # # * The jsdoc package is a JavaScript API document generator analogous to Doxygen # or JavaDoc, it is used by the docs target in the JavaScript binding. if (NOT NODE_PACKAGES_FOUND) # Check if the specified node.js package is already installed, if not install it. macro(InstallPackage varname name) execute_process( COMMAND npm list --local ${name} OUTPUT_VARIABLE check_package ) set(${varname} OFF) if (check_package MATCHES "${name}@.") message(STATUS "Found node.js package: ${name}") set(${varname} ON) else() message(STATUS "Installing node.js package: ${name}") execute_process( COMMAND npm install ${name} WORKING_DIRECTORY ${PROJECT_SOURCE_DIR} OUTPUT_VARIABLE var ) if (var) message(STATUS "Installed node.js package: ${name}") set(${varname} ON) endif (var) endif() endmacro() # Check if ws WebSocket library https://github.com/websockets/ws is installed # N.B. something changed between ws 0.5.0 and 0.6.0 that breaks proton js # so explicitly pulling version 0.5.0 # TODO update javascript binding/emscripten/both to work with latest ws. InstallPackage("NODE_WS_FOUND" "ws@0.5.0") # Check if jsdoc3 API documentation generator https://github.com/jsdoc3/jsdoc is installed InstallPackage("NODE_JSDOC_FOUND" "jsdoc") set(NODE_PACKAGES_FOUND ON) endif (NOT NODE_PACKAGES_FOUND) qpid-proton-0.14.0/tools/cmake/Modules/ProtonFindPerl.cmake0000644000175000017500000000554312770711161023073 0ustar danieldaniel# - Find Perl Libraries # This module searches for Perl libraries in the event that those files aren't # found by the default Cmake module. # include(${CMAKE_CURRENT_LIST_DIR}/FindPerlLibs.cmake) include(FindPerl) include(FindPerlLibs) if(NOT PERLLIBS_FOUND) MESSAGE ( STATUS "Trying alternative search for Perl" ) # taken from Cmake 2.8 FindPerlLibs.cmake EXECUTE_PROCESS ( COMMAND ${PERL_EXECUTABLE} -V:installarchlib OUTPUT_VARIABLE PERL_ARCHLIB_OUTPUT_VARIABLE RESULT_VARIABLE PERL_ARCHLIB_RESULT_VARIABLE ) if (NOT PERL_ARCHLIB_RESULT_VARIABLE) string(REGEX REPLACE "install[a-z]+='([^']+)'.*" "\\1" PERL_ARCHLIB ${PERL_ARCHLIB_OUTPUT_VARIABLE}) file(TO_CMAKE_PATH "${PERL_ARCHLIB}" PERL_ARCHLIB) endif ( NOT PERL_ARCHLIB_RESULT_VARIABLE ) EXECUTE_PROCESS ( COMMAND ${PERL_EXECUTABLE} -MConfig -e "print \$Config{archlibexp}" OUTPUT_VARIABLE PERL_OUTPUT RESULT_VARIABLE PERL_RETURN_VALUE ) IF ( NOT PERL_RETURN_VALUE ) FIND_PATH ( PERL_INCLUDE_PATH perl.h ${PERL_OUTPUT}/CORE ) IF (PERL_INCLUDE_PATH MATCHES .*-NOTFOUND OR NOT PERL_INCLUDE_PATH) MESSAGE(STATUS "Could not find perl.h") ENDIF () ENDIF ( NOT PERL_RETURN_VALUE ) # if either the library path is not found not set at all # then do our own search if ( NOT PERL_LIBRARY ) EXECUTE_PROCESS( COMMAND ${PERL_EXECUTABLE} -V:libperl OUTPUT_VARIABLE PERL_LIBRARY_OUTPUT RESULT_VARIABLE PERL_LIBRARY_RESULT ) IF ( NOT PERL_LIBRARY_RESULT ) string(REGEX REPLACE "libperl='([^']+)'.*" "\\1" PERL_POSSIBLE_LIBRARIES ${PERL_LIBRARY_OUTPUT}) ENDIF ( NOT PERL_LIBRARY_RESULT ) MESSAGE ( STATUS "Looking for ${PERL_POSSIBLE_LIBRARIES}" ) find_file(PERL_LIBRARY NAMES ${PERL_POSSIBLE_LIBRARIES} PATHS /usr/lib ${PERL_ARCHLIB}/CORE ) endif ( NOT PERL_LIBRARY ) IF ( PERL_LIBRARY MATCHES .*-NOTFOUND OR NOT PERL_LIBRARY ) EXECUTE_PROCESS ( COMMAND ${PERL_EXECUTABLE} -MConfig -e "print \$Config{libperl}" OUTPUT_VARIABLE PERL_OUTPUT RESULT_VARIABLE PERL_RETURN_VALUE ) IF ( NOT PERL_RETURN_VALUE ) FIND_LIBRARY ( PERL_LIBRARY NAMES ${PERL_OUTPUT} PATHS ${PERL_INCLUDE_PATH} ) ENDIF ( NOT PERL_RETURN_VALUE ) ENDIF ( PERL_LIBRARY MATCHES .*-NOTFOUND OR NOT PERL_LIBRARY ) IF(PERL_LIBRARY MATCHES .*-NOTFOUND OR NOT PERL_LIBRARY OR PERL_INCLUDE_PATH MATCHES .*-NOTFOUND OR NOT PERL_INCLUDE_PATH) MESSAGE (STATUS "No Perl devel environment found - skipping Perl bindings") SET (DEFAULT_PERL OFF) ELSE() MESSAGE ( STATUS "Found PerlLibs: ${PERL_LIBRARY}" ) SET (DEFAULT_PERL ON) ENDIF() endif(NOT PERLLIBS_FOUND) qpid-proton-0.14.0/tools/cmake/Modules/ProtonUseJava.cmake0000644000175000017500000000253312770711161022722 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # Adds a custom command to rebuild the JAR to include resources and the # directory entries that are missed by add_jar() function (rebuild_jar upstream_target jar_name) add_custom_command(TARGET ${upstream_target} POST_BUILD COMMAND ${Java_JAR_EXECUTABLE} cf ${jar_name} -C ${CMAKE_CURRENT_SOURCE_DIR}/src/main/resources . -C ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${upstream_target}.dir/ org COMMENT "Rebuilding ${jar_name} to include missing resources") endfunction () qpid-proton-0.14.0/tools/cmake/Modules/ProtonUseJavaSourceFileList.cmake0000644000175000017500000000513012770711161025533 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # Produces a text file containing a list of java source files from one # or more java source directories. Produces output suitable for use # with javac's @ source file argument. # # JAVA_SOURCE_DIR_PATHS - colon (:) separated string of java source directories # JAVA_SOURCE_FILE_LIST - name of text file to write # if (JAVA_SOURCE_DIR_PATHS) string(REPLACE ":" ";" JAVA_SOURCE_DIR_PATHS_LIST ${JAVA_SOURCE_DIR_PATHS}) message(STATUS "Java source paths: ${JAVA_SOURCE_DIR_PATHS}") set(_JAVA_GLOBBED_FILES) foreach(JAVA_SOURCE_DIR_PATH ${JAVA_SOURCE_DIR_PATHS_LIST}) if (EXISTS "${JAVA_SOURCE_DIR_PATH}") file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${JAVA_SOURCE_DIR_PATH}/*.java") if (_JAVA_GLOBBED_TMP_FILES) list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES}) endif () else () message(SEND_ERROR "FATAL: Java source path ${JAVA_SOURCE_DIR_PATH} doesn't exist") endif () endforeach() set (_CHECK_STALE OFF) set(_GENERATE_FILE_LIST ON) if (EXISTS ${JAVA_SOURCE_FILE_LIST}) set (_CHECK_STALE ON) set(_GENERATE_FILE_LIST OFF) endif () set(_JAVA_SOURCE_FILES_SEPARATED) foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) if (_CHECK_STALE) if (${_JAVA_GLOBBED_FILE} IS_NEWER_THAN ${JAVA_SOURCE_FILE_LIST}) set(_GENERATE_FILE_LIST ON) endif() endif() set(_JAVA_SOURCE_FILES_SEPARATED ${_JAVA_SOURCE_FILES_SEPARATED}${_JAVA_GLOBBED_FILE}\n) endforeach() if (_GENERATE_FILE_LIST) message(STATUS "Writing Java source file list to ${JAVA_SOURCE_FILE_LIST}") file(WRITE ${JAVA_SOURCE_FILE_LIST} ${_JAVA_SOURCE_FILES_SEPARATED}) endif() else () message(SEND_ERROR "FATAL: Can't find JAVA_SOURCE_DIR_PATHS") endif () qpid-proton-0.14.0/tools/cmake/Modules/README0000644000175000017500000000060212770711161020033 0ustar danieldanielCMake Modules ============= Contents: UseJava, UseJavaSymLinks, UseJavaClassFilelist: These are Andreas Schneider's CMake Java Support. We have our own local copy as all versions of CMake < 2.8.9 have defects in their Java support that affect us. Local modifications are commented with "Apache Qpid Proton...". UseProtonJava: Custom support functions for the Proton Java modules qpid-proton-0.14.0/tools/cmake/Modules/UseJavaClassFilelist.cmake0000644000175000017500000000421012770711161024174 0ustar danieldaniel# # This script create a list of compiled Java class files to be added to a # jar file. This avoids including cmake files which get created in the # binary directory. # #============================================================================= # Copyright 2010-2011 Andreas schneider # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) if (CMAKE_JAVA_CLASS_OUTPUT_PATH) if (EXISTS "${CMAKE_JAVA_CLASS_OUTPUT_PATH}") set(_JAVA_GLOBBED_FILES) if (CMAKE_JAR_CLASSES_PREFIX) foreach(JAR_CLASS_PREFIX ${CMAKE_JAR_CLASSES_PREFIX}) message(STATUS "JAR_CLASS_PREFIX: ${JAR_CLASS_PREFIX}") file(GLOB_RECURSE _JAVA_GLOBBED_TMP_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${JAR_CLASS_PREFIX}/*.class") if (_JAVA_GLOBBED_TMP_FILES) list(APPEND _JAVA_GLOBBED_FILES ${_JAVA_GLOBBED_TMP_FILES}) endif () endforeach() else() file(GLOB_RECURSE _JAVA_GLOBBED_FILES "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/*.class") endif () set(_JAVA_CLASS_FILES) # file(GLOB_RECURSE foo RELATIVE) is broken so we need this. foreach(_JAVA_GLOBBED_FILE ${_JAVA_GLOBBED_FILES}) file(RELATIVE_PATH _JAVA_CLASS_FILE ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ${_JAVA_GLOBBED_FILE}) set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES}${_JAVA_CLASS_FILE}\n) endforeach() # write to file file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist ${_JAVA_CLASS_FILES}) else () message(SEND_ERROR "FATAL: Java class output path doesn't exist") endif () else () message(SEND_ERROR "FATAL: Can't find CMAKE_JAVA_CLASS_OUTPUT_PATH") endif () qpid-proton-0.14.0/tools/cmake/Modules/UseJavaSymlinks.cmake0000644000175000017500000000213512770711161023250 0ustar danieldaniel# # Helper script for UseJava.cmake # #============================================================================= # Copyright 2010-2011 Andreas schneider # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) if (UNIX AND _JAVA_TARGET_OUTPUT_LINK) if (_JAVA_TARGET_OUTPUT_NAME) find_program(LN_EXECUTABLE NAMES ln ) execute_process( COMMAND ${LN_EXECUTABLE} -sf "${_JAVA_TARGET_OUTPUT_NAME}" "${_JAVA_TARGET_OUTPUT_LINK}" WORKING_DIRECTORY ${_JAVA_TARGET_DIR} ) else () message(SEND_ERROR "FATAL: Can't find _JAVA_TARGET_OUTPUT_NAME") endif () endif () qpid-proton-0.14.0/tools/cmake/Modules/WindowsC99CheckDef.cmake0000644000175000017500000000241112770711161023451 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # Check qpid-proton.dll after linking for dangerous calls to # Windows functions that suggest but deviate from C99 behavior: # _snprintf, vsnprintf, _vsnprintf # See platform.h for safe wrapper calls. # set(obj_dir ${CMAKE_CURRENT_BINARY_DIR}/qpid-proton.dir/${CMAKE_CFG_INTDIR}) add_custom_command(TARGET qpid-proton PRE_LINK COMMAND ${PYTHON_EXECUTABLE} ${CMAKE_MODULE_PATH}WindowsC99SymbolCheck.py ${obj_dir} COMMENT "Checking for dangerous use of C99-violating functions") qpid-proton-0.14.0/tools/cmake/Modules/WindowsC99SymbolCheck.py0000644000175000017500000000405712770711161023600 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # # # Stop cmake build if pn_i_xxx substitute functions aren't used for # the dangererous non-complying [v]snprintf family. A source of # painful bug-hunting. # # Each obj must be checked instead of just the dll since Visual Studio # sometimes inserts references to vsnprintf in DllMainCRTStartup, # causing false positives. # # bad: vsnprintf, __vsnprintf, _imp__vsnprintf, ..., same for snprintf # OK: vsnprintf_s, pn_i_vsnprintf # import sys import os import subprocess import glob import re def symcheck(objfile): symfile = objfile.replace('.obj', '.sym') cmd = ['dumpbin.exe', '/SYMBOLS', objfile, '/OUT:' + symfile] # /dev/null standin junk = open('junk', 'w') p = subprocess.Popen(cmd, stdout=junk) n = p.wait() if n != 0 : raise Exception("dumpbin call failure") f = open(symfile, 'r') for line in f : m = re.search(r'UNDEF.*\b([a-zA-Z_]*snprintf)\b', line) if m : sym = m.group(1) if re.match(r'_*pn_i_v?snprintf', sym) is None : raise Exception('Unsafe use of C99 violating function in ' + objfile + ' : ' + sym) def main(): os.chdir(sys.argv[1]) objs = glob.glob('*.obj') for obj in glob.glob('*.obj'): symcheck(obj) if __name__ == "__main__": sys.exit(main()) qpid-proton-0.14.0/tools/cmake/Modules/UseJava.cmake0000644000175000017500000011306612770711161021524 0ustar danieldaniel# - Use Module for Java # This file provides functions for Java. It is assumed that FindJava.cmake # has already been loaded. See FindJava.cmake for information on how to # load Java into your CMake project. # # add_jar(TARGET_NAME SRC1 SRC2 .. SRCN RCS1 RCS2 .. RCSN) # # This command creates a .jar. It compiles the given source # files (SRC) and adds the given resource files (RCS) to the jar file. # If only resource files are given then just a jar file is created. # # Additional instructions: # To add compile flags to the target you can set these flags with # the following variable: # # set(CMAKE_JAVA_COMPILE_FLAGS -nowarn) # # To add a path or a jar file to the class path you can do this # with the CMAKE_JAVA_INCLUDE_PATH variable. # # set(CMAKE_JAVA_INCLUDE_PATH /usr/share/java/shibboleet.jar) # # To use a different output name for the target you can set it with: # # set(CMAKE_JAVA_TARGET_OUTPUT_NAME shibboleet.jar) # add_jar(foobar foobar.java) # # To use a different output directory than CMAKE_CURRENT_BINARY_DIR # you can set it with: # # set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${PROJECT_BINARY_DIR}/bin) # # To define an entry point in your jar you can set it with: # # set(CMAKE_JAVA_JAR_ENTRY_POINT com/examples/MyProject/Main) # # To add a VERSION to the target output name you can set it using # CMAKE_JAVA_TARGET_VERSION. This will create a jar file with the name # shibboleet-1.0.0.jar and will create a symlink shibboleet.jar # pointing to the jar with the version information. # # set(CMAKE_JAVA_TARGET_VERSION 1.2.0) # add_jar(shibboleet shibbotleet.java) # # If the target is a JNI library, utilize the following commands to # create a JNI symbolic link: # # set(CMAKE_JNI_TARGET TRUE) # set(CMAKE_JAVA_TARGET_VERSION 1.2.0) # add_jar(shibboleet shibbotleet.java) # install_jar(shibboleet ${LIB_INSTALL_DIR}/shibboleet) # install_jni_symlink(shibboleet ${JAVA_LIB_INSTALL_DIR}) # # If a single target needs to produce more than one jar from its # java source code, to prevent the accumulation of duplicate class # files in subsequent jars, set/reset CMAKE_JAR_CLASSES_PREFIX prior # to calling the add_jar() function: # # set(CMAKE_JAR_CLASSES_PREFIX com/redhat/foo) # add_jar(foo foo.java) # # set(CMAKE_JAR_CLASSES_PREFIX com/redhat/bar) # add_jar(bar bar.java) # # Target Properties: # The add_jar() functions sets some target properties. You can get these # properties with the # get_property(TARGET PROPERTY ) # command. # # INSTALL_FILES The files which should be installed. This is used by # install_jar(). # JNI_SYMLINK The JNI symlink which should be installed. # This is used by install_jni_symlink(). # JAR_FILE The location of the jar file so that you can include # it. # CLASS_DIR The directory where the class files can be found. For # example to use them with javah. # # find_jar( # name | NAMES name1 [name2 ...] # [PATHS path1 [path2 ... ENV var]] # [VERSIONS version1 [version2]] # [DOC "cache documentation string"] # ) # # This command is used to find a full path to the named jar. A cache # entry named by is created to stor the result of this command. If # the full path to a jar is found the result is stored in the variable # and the search will not repeated unless the variable is cleared. If # nothing is found, the result will be -NOTFOUND, and the search # will be attempted again next time find_jar is invoked with the same # variable. # The name of the full path to a file that is searched for is specified # by the names listed after NAMES argument. Additional search locations # can be specified after the PATHS argument. If you require special a # version of a jar file you can specify it with the VERSIONS argument. # The argument after DOC will be used for the documentation string in # the cache. # # install_jar(TARGET_NAME DESTINATION) # # This command installs the TARGET_NAME files to the given DESTINATION. # It should be called in the same scope as add_jar() or it will fail. # # install_jni_symlink(TARGET_NAME DESTINATION) # # This command installs the TARGET_NAME JNI symlinks to the given # DESTINATION. It should be called in the same scope as add_jar() # or it will fail. # # create_javadoc( # PACKAGES pkg1 [pkg2 ...] # [SOURCEPATH ] # [CLASSPATH ] # [INSTALLPATH ] # [DOCTITLE "the documentation title"] # [WINDOWTITLE "the title of the document"] # [AUTHOR TRUE|FALSE] # [USE TRUE|FALSE] # [VERSION TRUE|FALSE] # ) # # Create java documentation based on files or packages. For more # details please read the javadoc manpage. # # There are two main signatures for create_javadoc. The first # signature works with package names on a path with source files: # # Example: # create_javadoc(my_example_doc # PACKAGES com.exmaple.foo com.example.bar # SOURCEPATH "${CMAKE_CURRENT_SOURCE_DIR}" # CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} # WINDOWTITLE "My example" # DOCTITLE "

My example

" # AUTHOR TRUE # USE TRUE # VERSION TRUE # ) # # The second signature for create_javadoc works on a given list of # files. # # create_javadoc( # FILES file1 [file2 ...] # [CLASSPATH ] # [INSTALLPATH ] # [DOCTITLE "the documentation title"] # [WINDOWTITLE "the title of the document"] # [AUTHOR TRUE|FALSE] # [USE TRUE|FALSE] # [VERSION TRUE|FALSE] # ) # # Example: # create_javadoc(my_example_doc # FILES ${example_SRCS} # CLASSPATH ${CMAKE_JAVA_INCLUDE_PATH} # WINDOWTITLE "My example" # DOCTITLE "

My example

" # AUTHOR TRUE # USE TRUE # VERSION TRUE # ) # # Both signatures share most of the options. These options are the # same as what you can find in the javadoc manpage. Please look at # the manpage for CLASSPATH, DOCTITLE, WINDOWTITLE, AUTHOR, USE and # VERSION. # # The documentation will be by default installed to # # ${CMAKE_INSTALL_PREFIX}/share/javadoc/ # # if you don't set the INSTALLPATH. # #============================================================================= # Copyright 2010-2011 Andreas schneider # Copyright 2010 Ben Boeckel # # Distributed under the OSI-approved BSD License (the "License"); # see accompanying file Copyright.txt for details. # # This software is distributed WITHOUT ANY WARRANTY; without even the # implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the License for more information. #============================================================================= # (To distribute this file outside of CMake, substitute the full # License text for the above reference.) function (__java_copy_file src dest comment) add_custom_command( OUTPUT ${dest} COMMAND cmake -E copy_if_different ARGS ${src} ${dest} DEPENDS ${src} COMMENT ${comment}) endfunction () # define helper scripts #set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaClassFilelist.cmake) #set(_JAVA_SYMLINK_SCRIPT ${CMAKE_CURRENT_LIST_DIR}/UseJavaSymlinks.cmake) set(_JAVA_CLASS_FILELIST_SCRIPT ${CMAKE_MODULE_PATH}/UseJavaClassFilelist.cmake) set(_JAVA_SYMLINK_SCRIPT ${CMAKE_MODULE_PATH}/UseJavaSymlinks.cmake) # Apache Qpid Proton: changed to write a source file list to avoid hitting # command line limits when processing many source files. function(add_jar _TARGET_NAME) set(_JAVA_SOURCE_FILES ${ARGN}) if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) endif() if (CMAKE_JAVA_JAR_ENTRY_POINT) set(_ENTRY_POINT_OPTION e) set(_ENTRY_POINT_VALUE ${CMAKE_JAVA_JAR_ENTRY_POINT}) endif () if (LIBRARY_OUTPUT_PATH) set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${LIBRARY_OUTPUT_PATH}) else () set(CMAKE_JAVA_LIBRARY_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}) endif () set(CMAKE_JAVA_INCLUDE_PATH ${CMAKE_JAVA_INCLUDE_PATH} ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_JAVA_OBJECT_OUTPUT_PATH} ${CMAKE_JAVA_LIBRARY_OUTPUT_PATH} ) if (WIN32 AND NOT CYGWIN) set(CMAKE_JAVA_INCLUDE_FLAG_SEP ";") else () set(CMAKE_JAVA_INCLUDE_FLAG_SEP ":") endif() foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH}) set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}") endforeach() set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir") set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar") if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") elseif (CMAKE_JAVA_TARGET_VERSION) set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar") elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME) set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") endif () # reset set(CMAKE_JAVA_TARGET_OUTPUT_NAME) set(_JAVA_CLASS_FILES) set(_JAVA_COMPILE_FILES) set(_JAVA_DEPENDS) set(_JAVA_RESOURCE_FILES) foreach(_JAVA_SOURCE_FILE ${_JAVA_SOURCE_FILES}) get_filename_component(_JAVA_EXT ${_JAVA_SOURCE_FILE} EXT) get_filename_component(_JAVA_FILE ${_JAVA_SOURCE_FILE} NAME_WE) get_filename_component(_JAVA_PATH ${_JAVA_SOURCE_FILE} PATH) get_filename_component(_JAVA_FULL ${_JAVA_SOURCE_FILE} ABSOLUTE) file(RELATIVE_PATH _JAVA_REL_BINARY_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR} ${_JAVA_FULL}) file(RELATIVE_PATH _JAVA_REL_SOURCE_PATH ${CMAKE_CURRENT_SOURCE_DIR} ${_JAVA_FULL}) string(LENGTH ${_JAVA_REL_BINARY_PATH} _BIN_LEN) string(LENGTH ${_JAVA_REL_SOURCE_PATH} _SRC_LEN) if (${_BIN_LEN} LESS ${_SRC_LEN}) set(_JAVA_REL_PATH ${_JAVA_REL_BINARY_PATH}) else () set(_JAVA_REL_PATH ${_JAVA_REL_SOURCE_PATH}) endif () get_filename_component(_JAVA_REL_PATH ${_JAVA_REL_PATH} PATH) if (_JAVA_EXT MATCHES ".java") list(APPEND _JAVA_COMPILE_FILES ${_JAVA_SOURCE_FILE}) set(_JAVA_CLASS_FILE "${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_REL_PATH}/${_JAVA_FILE}.class") set(_JAVA_CLASS_FILES ${_JAVA_CLASS_FILES} ${_JAVA_CLASS_FILE}) elseif (_JAVA_EXT MATCHES ".jar" OR _JAVA_EXT MATCHES ".war" OR _JAVA_EXT MATCHES ".ear" OR _JAVA_EXT MATCHES ".sar") list(APPEND CMAKE_JAVA_INCLUDE_PATH ${_JAVA_SOURCE_FILE}) elseif (_JAVA_EXT STREQUAL "") list(APPEND CMAKE_JAVA_INCLUDE_PATH ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}} ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}_CLASSPATH}) list(APPEND _JAVA_DEPENDS ${JAVA_JAR_TARGET_${_JAVA_SOURCE_FILE}}) else () __java_copy_file(${CMAKE_CURRENT_SOURCE_DIR}/${_JAVA_SOURCE_FILE} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/${_JAVA_SOURCE_FILE} "Copying ${_JAVA_SOURCE_FILE} to the build directory") list(APPEND _JAVA_RESOURCE_FILES ${_JAVA_SOURCE_FILE}) endif () endforeach() set(CMAKE_JAVA_SOURCE_FILE_LIST ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_source_filelist) string(REPLACE ";" "\n" _JAVA_COMPILE_FILES_NEWLINE_SEPARATED "${_JAVA_COMPILE_FILES}") file(WRITE ${CMAKE_JAVA_SOURCE_FILE_LIST} "${_JAVA_COMPILE_FILES_NEWLINE_SEPARATED}") # create an empty java_class_filelist if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist) file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "") endif() if (_JAVA_COMPILE_FILES) # Compile the java files and create a list of class files add_custom_command( # NOTE: this command generates an artificial dependency file OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} COMMAND ${Java_JAVAC_EXECUTABLE} ${CMAKE_JAVA_COMPILE_FLAGS} -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}" -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH} @${CMAKE_JAVA_SOURCE_FILE_LIST} COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} DEPENDS ${_JAVA_COMPILE_FILES} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Building Java objects for ${_TARGET_NAME}.jar" ) add_custom_command( OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist COMMAND ${CMAKE_COMMAND} -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH} -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}" -P ${_JAVA_CLASS_FILELIST_SCRIPT} DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) endif () # create the jar file set(_JAVA_JAR_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}) if (CMAKE_JNI_TARGET) add_custom_command( OUTPUT ${_JAVA_JAR_OUTPUT_PATH} COMMAND ${Java_JAR_EXECUTABLE} -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} ${_JAVA_RESOURCE_FILES} @java_class_filelist COMMAND ${CMAKE_COMMAND} -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} -P ${_JAVA_SYMLINK_SCRIPT} COMMAND ${CMAKE_COMMAND} -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_JAR_OUTPUT_PATH} -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} -P ${_JAVA_SYMLINK_SCRIPT} DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" ) else () add_custom_command( OUTPUT ${_JAVA_JAR_OUTPUT_PATH} COMMAND ${Java_JAR_EXECUTABLE} -cf${_ENTRY_POINT_OPTION} ${_JAVA_JAR_OUTPUT_PATH} ${_ENTRY_POINT_VALUE} ${_JAVA_RESOURCE_FILES} @java_class_filelist COMMAND ${CMAKE_COMMAND} -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} -P ${_JAVA_SYMLINK_SCRIPT} WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" ) endif () # Add the target and make sure we have the latest resource files. add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH}) set_property( TARGET ${_TARGET_NAME} PROPERTY INSTALL_FILES ${_JAVA_JAR_OUTPUT_PATH} ) if (_JAVA_TARGET_OUTPUT_LINK) set_property( TARGET ${_TARGET_NAME} PROPERTY INSTALL_FILES ${_JAVA_JAR_OUTPUT_PATH} ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} ) if (CMAKE_JNI_TARGET) set_property( TARGET ${_TARGET_NAME} PROPERTY JNI_SYMLINK ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} ) endif () endif () set_property( TARGET ${_TARGET_NAME} PROPERTY JAR_FILE ${_JAVA_JAR_OUTPUT_PATH} ) set_property( TARGET ${_TARGET_NAME} PROPERTY CLASSDIR ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ) endfunction() # Apache Qpid Proton: new function that accepts a file containing the Java source # files. This is useful when the set of source files is only discovered at make-time, # and avoids passing a wildcard argument to javac (which fails on some platforms) function(add_jar_from_filelist _TARGET_NAME CMAKE_JAVA_SOURCE_FILE_LIST) if (NOT DEFINED CMAKE_JAVA_TARGET_OUTPUT_DIR) set(CMAKE_JAVA_TARGET_OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) endif() set(CMAKE_JAVA_CLASS_OUTPUT_PATH "${CMAKE_JAVA_TARGET_OUTPUT_DIR}${CMAKE_FILES_DIRECTORY}/${_TARGET_NAME}.dir") set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}.jar") if (CMAKE_JAVA_TARGET_OUTPUT_NAME AND CMAKE_JAVA_TARGET_VERSION) set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") set(_JAVA_TARGET_OUTPUT_LINK "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") elseif (CMAKE_JAVA_TARGET_VERSION) set(_JAVA_TARGET_OUTPUT_NAME "${_TARGET_NAME}-${CMAKE_JAVA_TARGET_VERSION}.jar") set(_JAVA_TARGET_OUTPUT_LINK "${_TARGET_NAME}.jar") elseif (CMAKE_JAVA_TARGET_OUTPUT_NAME) set(_JAVA_TARGET_OUTPUT_NAME "${CMAKE_JAVA_TARGET_OUTPUT_NAME}.jar") endif () # reset set(CMAKE_JAVA_TARGET_OUTPUT_NAME) foreach (JAVA_INCLUDE_DIR ${CMAKE_JAVA_INCLUDE_PATH}) set(CMAKE_JAVA_INCLUDE_PATH_FINAL "${CMAKE_JAVA_INCLUDE_PATH_FINAL}${CMAKE_JAVA_INCLUDE_FLAG_SEP}${JAVA_INCLUDE_DIR}") endforeach() # create an empty java_class_filelist if (NOT EXISTS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist) file(WRITE ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist "") endif () # Compile the java files and create a list of class files add_custom_command( # NOTE: this command generates an artificial dependency file OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} COMMAND ${Java_JAVAC_EXECUTABLE} ${CMAKE_JAVA_COMPILE_FLAGS} -classpath "${CMAKE_JAVA_INCLUDE_PATH_FINAL}" -d ${CMAKE_JAVA_CLASS_OUTPUT_PATH} @${CMAKE_JAVA_SOURCE_FILE_LIST} COMMAND ${CMAKE_COMMAND} -E touch ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} DEPENDS ${CMAKE_JAVA_SOURCE_FILE_LIST} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} COMMENT "Building Java objects for ${_TARGET_NAME}.jar" ) add_custom_command( OUTPUT ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist COMMAND ${CMAKE_COMMAND} -DCMAKE_JAVA_CLASS_OUTPUT_PATH=${CMAKE_JAVA_CLASS_OUTPUT_PATH} -DCMAKE_JAR_CLASSES_PREFIX="${CMAKE_JAR_CLASSES_PREFIX}" -P ${_JAVA_CLASS_FILELIST_SCRIPT} DEPENDS ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_compiled_${_TARGET_NAME} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) # create the jar file set(_JAVA_JAR_OUTPUT_PATH ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_NAME}) add_custom_command( OUTPUT ${_JAVA_JAR_OUTPUT_PATH} COMMAND ${Java_JAR_EXECUTABLE} -cf ${_JAVA_JAR_OUTPUT_PATH} ${_JAVA_RESOURCE_FILES} @java_class_filelist COMMAND ${CMAKE_COMMAND} -D_JAVA_TARGET_DIR=${CMAKE_JAVA_TARGET_OUTPUT_DIR} -D_JAVA_TARGET_OUTPUT_NAME=${_JAVA_TARGET_OUTPUT_NAME} -D_JAVA_TARGET_OUTPUT_LINK=${_JAVA_TARGET_OUTPUT_LINK} -P ${_JAVA_SYMLINK_SCRIPT} WORKING_DIRECTORY ${CMAKE_JAVA_CLASS_OUTPUT_PATH} DEPENDS ${_JAVA_RESOURCE_FILES} ${_JAVA_DEPENDS} ${CMAKE_JAVA_CLASS_OUTPUT_PATH}/java_class_filelist COMMENT "Creating Java archive ${_JAVA_TARGET_OUTPUT_NAME}" ) # Add the target and make sure we have the latest resource files. add_custom_target(${_TARGET_NAME} ALL DEPENDS ${_JAVA_JAR_OUTPUT_PATH}) set_property( TARGET ${_TARGET_NAME} PROPERTY INSTALL_FILES ${_JAVA_JAR_OUTPUT_PATH} ) if (_JAVA_TARGET_OUTPUT_LINK) set_property( TARGET ${_TARGET_NAME} PROPERTY INSTALL_FILES ${_JAVA_JAR_OUTPUT_PATH} ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} ) if (CMAKE_JNI_TARGET) set_property( TARGET ${_TARGET_NAME} PROPERTY JNI_SYMLINK ${CMAKE_JAVA_TARGET_OUTPUT_DIR}/${_JAVA_TARGET_OUTPUT_LINK} ) endif () endif () set_property( TARGET ${_TARGET_NAME} PROPERTY JAR_FILE ${_JAVA_JAR_OUTPUT_PATH} ) set_property( TARGET ${_TARGET_NAME} PROPERTY CLASSDIR ${CMAKE_JAVA_CLASS_OUTPUT_PATH} ) endfunction() # Apache Qpid Proton: make the install files optional so as not to error if there is no symlink function(INSTALL_JAR _TARGET_NAME _DESTINATION) get_property(__FILES TARGET ${_TARGET_NAME} PROPERTY INSTALL_FILES ) if (__FILES) install( FILES ${__FILES} DESTINATION ${_DESTINATION} OPTIONAL ) else () message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") endif () endfunction() function(INSTALL_JNI_SYMLINK _TARGET_NAME _DESTINATION) get_property(__SYMLINK TARGET ${_TARGET_NAME} PROPERTY JNI_SYMLINK ) if (__SYMLINK) install( FILES ${__SYMLINK} DESTINATION ${_DESTINATION} ) else () message(SEND_ERROR "The target ${_TARGET_NAME} is not known in this scope.") endif () endfunction() function (find_jar VARIABLE) set(_jar_names) set(_jar_files) set(_jar_versions) set(_jar_paths /usr/share/java/ /usr/local/share/java/ ${Java_JAR_PATHS}) set(_jar_doc "NOTSET") set(_state "name") foreach (arg ${ARGN}) if (${_state} STREQUAL "name") if (${arg} STREQUAL "VERSIONS") set(_state "versions") elseif (${arg} STREQUAL "NAMES") set(_state "names") elseif (${arg} STREQUAL "PATHS") set(_state "paths") elseif (${arg} STREQUAL "DOC") set(_state "doc") else () set(_jar_names ${arg}) if (_jar_doc STREQUAL "NOTSET") set(_jar_doc "Finding ${arg} jar") endif () endif () elseif (${_state} STREQUAL "versions") if (${arg} STREQUAL "NAMES") set(_state "names") elseif (${arg} STREQUAL "PATHS") set(_state "paths") elseif (${arg} STREQUAL "DOC") set(_state "doc") else () set(_jar_versions ${_jar_versions} ${arg}) endif () elseif (${_state} STREQUAL "names") if (${arg} STREQUAL "VERSIONS") set(_state "versions") elseif (${arg} STREQUAL "PATHS") set(_state "paths") elseif (${arg} STREQUAL "DOC") set(_state "doc") else () set(_jar_names ${_jar_names} ${arg}) if (_jar_doc STREQUAL "NOTSET") set(_jar_doc "Finding ${arg} jar") endif () endif () elseif (${_state} STREQUAL "paths") if (${arg} STREQUAL "VERSIONS") set(_state "versions") elseif (${arg} STREQUAL "NAMES") set(_state "names") elseif (${arg} STREQUAL "DOC") set(_state "doc") else () set(_jar_paths ${_jar_paths} ${arg}) endif () elseif (${_state} STREQUAL "doc") if (${arg} STREQUAL "VERSIONS") set(_state "versions") elseif (${arg} STREQUAL "NAMES") set(_state "names") elseif (${arg} STREQUAL "PATHS") set(_state "paths") else () set(_jar_doc ${arg}) endif () endif () endforeach () if (NOT _jar_names) message(FATAL_ERROR "find_jar: No name to search for given") endif () foreach (jar_name ${_jar_names}) foreach (version ${_jar_versions}) set(_jar_files ${_jar_files} ${jar_name}-${version}.jar) endforeach () set(_jar_files ${_jar_files} ${jar_name}.jar) endforeach () find_file(${VARIABLE} NAMES ${_jar_files} PATHS ${_jar_paths} DOC ${_jar_doc} NO_DEFAULT_PATH) endfunction () function(create_javadoc _target) set(_javadoc_packages) set(_javadoc_files) set(_javadoc_sourcepath) set(_javadoc_classpath) set(_javadoc_installpath "${CMAKE_INSTALL_PREFIX}/share/javadoc") set(_javadoc_doctitle) set(_javadoc_windowtitle) set(_javadoc_author FALSE) set(_javadoc_version FALSE) set(_javadoc_use FALSE) set(_state "package") foreach (arg ${ARGN}) if (${_state} STREQUAL "package") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_packages ${arg}) set(_state "packages") endif () elseif (${_state} STREQUAL "packages") if (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () list(APPEND _javadoc_packages ${arg}) endif () elseif (${_state} STREQUAL "files") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () list(APPEND _javadoc_files ${arg}) endif () elseif (${_state} STREQUAL "sourcepath") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () list(APPEND _javadoc_sourcepath ${arg}) endif () elseif (${_state} STREQUAL "classpath") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () list(APPEND _javadoc_classpath ${arg}) endif () elseif (${_state} STREQUAL "installpath") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_installpath ${arg}) endif () elseif (${_state} STREQUAL "doctitle") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_doctitle ${arg}) endif () elseif (${_state} STREQUAL "windowtitle") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_windowtitle ${arg}) endif () elseif (${_state} STREQUAL "author") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_author ${arg}) endif () elseif (${_state} STREQUAL "use") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_use ${arg}) endif () elseif (${_state} STREQUAL "version") if (${arg} STREQUAL "PACKAGES") set(_state "packages") elseif (${arg} STREQUAL "FILES") set(_state "files") elseif (${arg} STREQUAL "SOURCEPATH") set(_state "sourcepath") elseif (${arg} STREQUAL "CLASSPATH") set(_state "classpath") elseif (${arg} STREQUAL "INSTALLPATH") set(_state "installpath") elseif (${arg} STREQUAL "DOCTITLE") set(_state "doctitle") elseif (${arg} STREQUAL "WINDOWTITLE") set(_state "windowtitle") elseif (${arg} STREQUAL "AUTHOR") set(_state "author") elseif (${arg} STREQUAL "USE") set(_state "use") elseif (${arg} STREQUAL "VERSION") set(_state "version") else () set(_javadoc_version ${arg}) endif () endif () endforeach () set(_javadoc_builddir ${CMAKE_CURRENT_BINARY_DIR}/javadoc/${_target}) set(_javadoc_options -d ${_javadoc_builddir}) if (_javadoc_sourcepath) set(_start TRUE) foreach(_path ${_javadoc_sourcepath}) if (_start) set(_sourcepath ${_path}) set(_start FALSE) else () set(_sourcepath ${_sourcepath}:${_path}) endif () endforeach() set(_javadoc_options ${_javadoc_options} -sourcepath ${_sourcepath}) endif () if (_javadoc_classpath) set(_start TRUE) foreach(_path ${_javadoc_classpath}) if (_start) set(_classpath ${_path}) set(_start FALSE) else () set(_classpath ${_classpath}:${_path}) endif () endforeach() set(_javadoc_options ${_javadoc_options} -classpath "${_classpath}") endif () if (_javadoc_doctitle) set(_javadoc_options ${_javadoc_options} -doctitle '${_javadoc_doctitle}') endif () if (_javadoc_windowtitle) set(_javadoc_options ${_javadoc_options} -windowtitle '${_javadoc_windowtitle}') endif () if (_javadoc_author) set(_javadoc_options ${_javadoc_options} -author) endif () if (_javadoc_use) set(_javadoc_options ${_javadoc_options} -use) endif () if (_javadoc_version) set(_javadoc_options ${_javadoc_options} -version) endif () add_custom_target(${_target}_javadoc ALL COMMAND ${Java_JAVADOC_EXECUTABLE} ${_javadoc_options} ${_javadoc_files} ${_javadoc_packages} WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} ) install( DIRECTORY ${_javadoc_builddir} DESTINATION ${_javadoc_installpath} ) endfunction() qpid-proton-0.14.0/tools/check_abi/0000755000175000017500000000000012770711161016355 5ustar danieldanielqpid-proton-0.14.0/tools/check_abi/README.md0000644000175000017500000000072012770711161017633 0ustar danieldanielThis is a tool for looking at the ELF symbols exported by a C/C++ shared library. Currently it has some rough edges, but it will take a file of expected symbols and tell you the difference from what is ewxpected. Currently you also need to compile the C++ programs in the same directory to support the script Besides the compiled programs in this directory it also relies on GNU nm to extract the symbols and some standard POSIX utilities for text manipulation.qpid-proton-0.14.0/tools/check_abi/check-abi0000755000175000017500000000355212770711161020116 0ustar danieldaniel#!/usr/bin/env bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # MKTEMP="mktemp /tmp/tmp.XXXXXXXXXX" rc=0 syms_desired=$($MKTEMP) syms_library=$($MKTEMP) syms_missing=$($MKTEMP) syms_extra=$($MKTEMP) trap 'rm $syms_desired $syms_library $syms_missing $syms_extra' EXIT if [[ $# -lt 2 ]] ; then echo "Usage:" echo "check_abi object_file expected_symbols_file" exit 1; fi LC_ALL=C export LC_ALL # Extract exported symbols from library nm -DC --defined-only -f s $1 | cut -f1 -d'|' -s | sed -e "$(./cppabi)" -e "s/ *$//" | sort -u > $syms_library # Process API syms (substitute in some typedefs etc.) sed -e " $(./expand_types) /^\$/d /^#.*\$/d " $2 | sort -u > $syms_desired comm -23 $syms_desired $syms_library > $syms_missing comm -13 $syms_desired $syms_library > $syms_extra if [[ -n "$(cat $syms_missing)" ]] ; then (echo "Not exported from library (should be)" echo "=====================================" cat $syms_missing ) 1>&2 rc=1 fi if [[ -n "$(cat $syms_extra)" ]]; then (echo "Exported by library but not in spec" echo "===================================" cat $syms_extra ) 1>&2 fi exit $rc qpid-proton-0.14.0/tools/check_abi/cppabi.cpp0000644000175000017500000000171512770711161020323 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include int main() { #if _GLIBCXX_USE_CXX11_ABI std::cout << "s/\\[abi:cxx11\\]//"; return 0; #else return 1; #endif } qpid-proton-0.14.0/tools/check_abi/expand_types.cpp0000644000175000017500000000312412770711161021564 0ustar danieldaniel/* * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * */ #include #include #include #include #include #include #include void print_type(const char* type, const char* mangled_type) { int status; char* demangled_type = abi::__cxa_demangle(mangled_type, 0, 0, &status); if (demangled_type) { std::cout << "s/" << type << "/" << demangled_type << "/g\n"; } ::free(demangled_type); } #define mangle_name(x) typeid(x).name() #define print_subst(x) print_type(#x, mangle_name(x)) int main() { print_subst(uint64_t); print_subst(uint32_t); print_subst(uint16_t); print_subst(uint8_t); print_subst(size_t); print_subst(int64_t); print_subst(int32_t); print_subst(int16_t); print_subst(int8_t); print_subst(std::string); print_subst(std::vector); } qpid-proton-0.14.0/.gitignore0000644000175000017500000000123412770711161015315 0ustar danieldaniel# Emacs, vim etc *~ *.swp # Start of IntelliJ IDE files .idea .idea/* *.iml *.ipr *.iws # End of IntelliJ IDE files /build/ *.class *.pyc *.pyo target # MacOS File .DS_Store # Start of Eclipse IDE files .project .classpath .settings .cproject eclipse-classes .pydevproject # End of Eclipse IDE files # The usual location for proton-c build files proton-c/build # Executables built by go binding tests proton-c/bindings/go/bin # Testresults from the jenkins build script testresults # Go binding build output /proton-c/bindings/go/pkg /proton-c/bindings/go/bin # Python TOX test build output /proton-c/bindings/python/MANIFEST /proton-c/bindings/python/build qpid-proton-0.14.0/.reviewboardrc0000644000175000017500000000012112770711161016156 0ustar danieldanielREVIEWBOARD_URL = "https://reviews.apache.org" REPOSITORY = 'qpid-proton-git' qpid-proton-0.14.0/.travis.yml0000644000175000017500000000110512770711161015433 0ustar danieldanielos: - linux sudo: false language: - python python: - 2.7 addons: apt: packages: - cmake - libssl-dev - libsasl2-dev - sasl2-bin - swig - python-dev - valgrind - ruby - ruby-dev - python3-dev - php5 - openjdk-7-jdk install: - pip install --upgrade pip - pip install tox - gem install rspec - gem install simplecov || true - gem install minitest before_script: - export PATH=${HOME}/.local/bin:${PATH} - mkdir Build - cd Build - cmake .. -DCMAKE_INSTALL_PREFIX=$PWD/install script: - cmake --build . --target install && ctest -V qpid-proton-0.14.0/CMakeLists.txt0000644000175000017500000001532412770711161016072 0ustar danieldaniel# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # cmake_minimum_required (VERSION 2.8.7) project (Proton C) # Enable C++ now for examples and bindings subdirectories, but make it optional. enable_language(CXX OPTIONAL) if (MSVC) # No C99 capability, use C++ set(DEFAULT_BUILD_WITH_CXX ON) endif (MSVC) option(BUILD_WITH_CXX "Compile Proton using C++" ${DEFAULT_BUILD_WITH_CXX}) if (CMAKE_CONFIGURATION_TYPES) # There is no single "build type"... message(STATUS "Build types are ${CMAKE_CONFIGURATION_TYPES}") else (CMAKE_CONFIGURATION_TYPES) # There is a single build configuration # If the build type is not set then set the default if (NOT CMAKE_BUILD_TYPE) set (CMAKE_BUILD_TYPE RelWithDebInfo CACHE string "Build type: Debug, Release, RelWithDebInfo or MinSizeRel (default RelWithDebInfo)" FORCE) endif () if (CMAKE_BUILD_TYPE MATCHES "Deb") set (has_debug_symbols " (has debug symbols)") endif (CMAKE_BUILD_TYPE MATCHES "Deb") message(STATUS "Build type is \"${CMAKE_BUILD_TYPE}\"${has_debug_symbols}") endif (CMAKE_CONFIGURATION_TYPES) if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin") # Default to universal binary on Mac OS X unless user has overriden if (NOT DEFINED CMAKE_OSX_ARCHITECTURES OR "${CMAKE_OSX_ARCHITECTURES}" STREQUAL "") set(CMAKE_OSX_ARCHITECTURES "i386;x86_64") endif () endif () file(READ version.txt PN_VERSION_FILE) string(STRIP ${PN_VERSION_FILE} PN_VERSION_LINE) string(REPLACE "-" ";" PN_VERSION_SPLIT "${PN_VERSION_LINE}") list(GET PN_VERSION_SPLIT 0 PN_VERSION_CLEAN) list(REMOVE_AT PN_VERSION_SPLIT 0) string(REPLACE ";" "-" PN_VERSION_QUALIFIER "${PN_VERSION_SPLIT}") string(REGEX MATCHALL "[0-9]+" PN_VERSION_LIST "${PN_VERSION_CLEAN}") list(GET PN_VERSION_LIST 0 PN_VERSION_MAJOR) list(GET PN_VERSION_LIST 1 PN_VERSION_MINOR) list(LENGTH PN_VERSION_LIST PN_VERSION_LENGTH) if (${PN_VERSION_LENGTH} GREATER 2) list(GET PN_VERSION_LIST 2 PN_VERSION_POINT) set (PN_VERSION "${PN_VERSION_MAJOR}.${PN_VERSION_MINOR}.${PN_VERSION_POINT}") else() set (PN_VERSION_POINT 0) set (PN_VERSION "${PN_VERSION_MAJOR}.${PN_VERSION_MINOR}") endif() message(STATUS "PN_VERSION: ${PN_VERSION} (${PN_VERSION_QUALIFIER})") enable_testing() include (CTest) set (pn_test_root "${CMAKE_CURRENT_SOURCE_DIR}/tests") set (pn_test_bin "${CMAKE_CURRENT_BINARY_DIR}/tests") # In rpm builds the build sets some variables: # CMAKE_INSTALL_PREFIX - this is a standard cmake variable # INCLUDE_INSTALL_DIR # LIB_INSTALL_DIR # SYSCONF_INSTALL_DIR # SHARE_INSTALL_DIR # So make these cached variables and the specific variables non cached # and derived from them. if (NOT DEFINED LIB_SUFFIX) get_property(LIB64 GLOBAL PROPERTY FIND_LIBRARY_USE_LIB64_PATHS) if ("${LIB64}" STREQUAL "TRUE" AND ${CMAKE_SIZEOF_VOID_P} STREQUAL "8") set(LIB_SUFFIX 64) else() set(LIB_SUFFIX "") endif() endif() # Start of variables used during install set (INCLUDE_INSTALL_DIR include CACHE PATH "Include file directory") set (LIB_INSTALL_DIR "lib${LIB_SUFFIX}" CACHE PATH "Library object file directory") set (SYSCONF_INSTALL_DIR etc CACHE PATH "System read only configuration directory") set (SHARE_INSTALL_DIR share CACHE PATH "Shared read only data directory") set (MAN_INSTALL_DIR share/man CACHE PATH "Manpage directory") mark_as_advanced (INCLUDE_INSTALL_DIR LIB_INSTALL_DIR SYSCONF_INSTALL_DIR SHARE_INSTALL_DIR MAN_INSTALL_DIR) ## LANGUAGE BINDINGS # Default directory for language bindings not being installed into # system specified locations. set (BINDINGS_DIR ${LIB_INSTALL_DIR}/proton/bindings) set (SYSINSTALL_BINDINGS OFF CACHE BOOL "If SYSINSTALL_BINDINGS is OFF then proton bindings will be installed underneath ${BINDINGS_DIR} and each user will need to modify their interpreter configuration to load the appropriate binding. If SYSINSTALL_BINDINGS is ON, then each language interpreter will be queried for the appropriate directory and proton bindings will be installed and available system wide with no additional per user configuration.") set (BINDING_LANGS PERL PHP PYTHON RUBY) foreach (LANG ${BINDING_LANGS}) set (SYSINSTALL_${LANG} OFF CACHE BOOL "Install ${LANG} bindings into interpreter specified location.") if (SYSINSTALL_BINDINGS OR SYSINSTALL_${LANG}) set (CHECK_SYSINSTALL_${LANG} ON) else () set (CHECK_SYSINSTALL_${LANG} OFF) endif () endforeach() set (PROTON_SHARE ${SHARE_INSTALL_DIR}/proton-${PN_VERSION}) # End of variables used during install # Pull in local cmake modules set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/tools/cmake/Modules/") find_package(Java) option (BUILD_JAVA "Build proton-j." ${JAVA_FOUND}) if (BUILD_JAVA) add_subdirectory(proton-j) endif() # Check for valgrind here so tests under proton-c/ and examples/ can use it. find_program(VALGRIND_EXE valgrind DOC "Location of the valgrind program") option(ENABLE_VALGRIND "Use valgrind to detect run-time problems" ON) if (ENABLE_VALGRIND) if (NOT VALGRIND_EXE) message(STATUS "Can't locate the valgrind command; no run-time error detection") else () set (VALGRIND_ENV "VALGRIND=${VALGRIND_EXE}") endif () endif (ENABLE_VALGRIND) mark_as_advanced (VALGRIND_EXE) add_subdirectory(proton-c) add_subdirectory(examples) install (FILES LICENSE README.md TODO DESTINATION ${PROTON_SHARE}) install (DIRECTORY examples DESTINATION ${PROTON_SHARE} REGEX "/examples/CMakeLists.txt$" EXCLUDE PATTERN "*Config.cmake" EXCLUDE) # add relevant CTest support find_program (MAVEN_EXE mvn DOC "Location of the maven program") mark_as_advanced (MAVEN_EXE) if (JAVA_FOUND AND MAVEN_EXE) add_test (proton-java ${MAVEN_EXE} clean test --file ${Proton_SOURCE_DIR}/pom.xml) else (JAVA_FOUND AND MAVEN_EXE) message (STATUS "Cannot find both Java and Maven: testing disabled for Proton-J") endif (JAVA_FOUND AND MAVEN_EXE) # Generate test environment settings configure_file(${CMAKE_SOURCE_DIR}/config.sh.in ${CMAKE_BINARY_DIR}/config.sh @ONLY) configure_file(${CMAKE_SOURCE_DIR}/config.bat.in ${CMAKE_BINARY_DIR}/config.bat @ONLY) qpid-proton-0.14.0/DEVELOPERS.md0000644000175000017500000001015712770711161015323 0ustar danieldanielQpid Proton Developer Information ================================= Please see http://qpid.apache.org/proton/development.html for the current roadmap. Development Environment ----------------------- Developers wishing to work across multiple languages should become familiar with the CMake build system as this will build and run all available tests and code whereas the maven build system only run Java tests. First you will need to set up your basic build environment with CMake and all prerequisites (see the instructions in INSTALL) so that you can build the full code base. To setup shell variables for your development environment, you must source the file config.sh from the CMake build directory. $ cd build $ source config.sh This file sets the necessary environment variables for Java, for all supported dynamic languages (Python, Perl, Ruby, PHP) and for running the tests. Testing ------- As a developer on Proton, it is a good idea to build and test with the appropriate dependencies and settings in place so that the complete set of language bindings and implementations are present. Note that there is a common test suite written in python which will run against both the proton-c and proton-j implementations to help keep them in sync with each other. This can be found under the top level `tests/python` directory. This has been integrated into the maven build via Jython (and is hence included in the proton-java ctest suite). When you run the python test suite in Jython, the swig generated cproton doesn't actually exist since it is a C module. Instead, you get the `cproton.py` that resides in the Java source tree under `proton-j/src/main/resources`. This `cproton.py` and its dependent files serve as a shim that adapts between the Java API and the C API. ### Running tests To test Proton you should use the CMake build. By default this will invoke the maven tests as well, so the maven prerequisites will additionally be required. By default the unit tests are run using the system's default Python interpreter. However, Proton's Python language bindings support both versions of the python language (Python 2.x and Python 3.x). These bindings should be tested using both versions of the Python interpreter. CMake makes this possible by automatically running the python unit tests under all versions of python installed on the system. Developers can ensure that Proton remains compatible with both versions of Python by installing the following prerequisites: _Note: currently CMake only supports multi-Python testing in **Linux** based environments. Non-Linux developers may skip the following two steps._ 1. Installing both Python2.x and Python3.x and their associated development environments on your system. Most modern Linux distributions support installing Python 2.x and Python 3.x in parallel. 2. Install the **tox** Python testing tool, (e.g. for Fedora): $ yum install python-tox To run the tests, cd into your build directory and use the following commands: # to run all the tests, summary mode $ ctest # to list the available testsuites $ ctest -N # to run a single testsuite, verbose output $ ctest -V -R c-engine-tests Additional packages required for testing the language bindings: # ruby dependencies $ yum install rubygem-minitest rubygem-rspec rubygem-simplecov # alternatively ruby depedencies on non-RPM based systems $ gem install minitest rspec simplecov If wishing to run a particular subset of python tests against proton-j, a pattern can be set via the Java system property "proton.pythontest.pattern" when running the Maven build directly: # Run the tests in transport.py class ClientTransportTest against proton-j: $ mvn test -Dproton.pythontest.pattern='proton_tests.transport.ClientTransportTest.*' Mailing list ------------ Subscribe to the Qpid Proton mailing list here: http://qpid.apache.org/proton/mailing_lists.html Patches ------- The best way to submit patches is to create a bug report or feature request on the project's JIRA instance: http://issues.apache.org/jira/browse/PROTON You can attach any patch(es) to the report/request there qpid-proton-0.14.0/INSTALL.md0000644000175000017500000001461212770711161014761 0ustar danieldanielQpid Proton Install Information =============================== Proton comes with two separate build systems. The CMake build system can builds the entire codebase, including proton-c, all proton-c language bindings, and the pure Java proton-j implementation. The maven build system can only build the Java portions of the code. CMake (Linux) ------------- The following prerequisites are required to do a full build on RPM based systems (RHEL, Fedora etc.). If you do not wish to build a given language binding you can omit the devel package for that language: # required dependencies $ yum install gcc cmake libuuid-devel # dependencies needed for ssl support $ yum install openssl-devel # dependencies needed for Cyrus SASL support $ yum install cyrus-sasl-devel # dependencies needed for bindings $ yum install swig python-devel ruby-devel php-devel perl-devel # dependencies needed for java (note that any non-ancient jvm will # work, 1.8.0 is just what is current for fedora 23) $ yum install java-1.8.0-openjdk-devel # dependencies needed for python docs $ yum install epydoc The following prerequisites are required to do a full build on Debian based systems (Ubuntu). If you do not wish to build a given language binding you can omit the dev package for that language: # Required dependencies $ apt-get install gcc cmake cmake-curses-gui uuid-dev # dependencies needed for ssl support $ apt-get install libssl-dev # dependencies needed for Cyrus SASL support $ apt-get install libsasl2-2 libsasl2-dev # dependencies needed for bindings $ apt-get install swig python-dev ruby-dev libperl-dev # dependencies needed for java (note that any non-ancient jvm will # work, 1.8.0 is just what is current for ubuntu 14) $ apt-get install openjdk-8-jdk # dependencies needed for python docs $ apt-get install python-epydoc From the directory where you found this README file: $ mkdir build $ cd build # Set the install prefix. You may need to adjust depending on your # system. $ cmake .. -DCMAKE_INSTALL_PREFIX=/usr -DSYSINSTALL_BINDINGS=ON # Omit the docs target if you do not wish to build or install # documentation. $ make all docs # Note that this step will require root privileges. $ make install When make install completes, all installed files are listed in the install_manifest.txt file. The contents of this file may be used to uninstall. Note: When SYSINSTALL_BINDINGS is enabled (ON), the CMAKE_INSTALL_PREFIX does not affect the location for where the language bindings (Python, Perl, PHP, Ruby) are installed. For those elements, the location is determined by the language interpreter itself; i.e., each interpreter is queried for the proper location for extensions. If you want to constrain where the Proton code is installed, set SYSINSTALL_BINDINGS to OFF. This will install all bindings to a common location under ${CMAKE_INSTALL_PREFIX}. When installed like this, each user will need to manually configure their interpreters with the respective binding location. CMake (Windows) --------------- This describes how to build the Proton library on Windows using Microsoft Visual C++. The Proton build uses the CMake tool to generate the Visual Studio project files. These project files can then be loaded into Visual Studio and used to build the Proton library. The following packages must be installed: - Visual Studio 2005 or newer (regular or C++ Express) - Python (www.python.org) - CMake (www.cmake.org) Additional packages are required for the language bindings - swig (www.swig.org) - development headers and libraries for the language of choice Notes: - be sure to install relevant Microsoft Service Packs and updates - python.exe, cmake.exe and swig.exe _must_ all be added to your PATH To generate the Visual Studio project files, from the directory where you found this README file: > mkdir build > cd build > cmake .. If CMake doesn't guess things correctly, useful additional arguments are: -G "Visual Studio 10" -DSWIG_EXECUTABLE=C:\swigwin-2.0.7\swig.exe Refer to the CMake documentation for more information. Build and install from a command prompt (using msbuild) > cmake --build . --target install --config RelWithDebInfo Loading the ALL_BUILD project into Visual Studio 1. Run the Microsoft Visual Studio IDE 2. From within the IDE, open the ALL_BUILD project file or proton solution file - it should be in the 'build' directory you created above. 3. Select the appropriate configuration. RelWithDebInfo works best with the included CMake/CTest scripts Note that if you wish to build debug version of proton for use with swig bindings on Windows, you must have the appropriate debug target libraries to link against. Installing Language Bindings ---------------------------- Most dynamic languages provide a way for asking where to install libraries in order to place them in a default search path. When SYSINSTALL_BINDINGS is disabled (OFF), Proton installs all dynamic language bindings into a central, default location: BINDINGS=${CMAKE_INSTALL_PREFIX}/${LIB_INSTALL_DIR}/proton/bindings In order to use these bindings, you'll need to configure your interpreter to load the bindings from the appropriate directory: * Perl - Add ${BINDINGS}/perl to PERL5LIB * PHP - Set the PHPRC envvar to point to ${BINDINGS}/php/proton.ini * Python - Add ${BINDINGS}/python to PYTHONPATH * Ruby - Add ${BINDINGS}/ruby to RUBYLIB You can configure the build to install a specific binding to the location specified by the system interpreter with the SYSINSTALL_[LANGUAGE] options, where [LANGUAGE] is one of JAVA, PERL, PHP, PYTHON, or RUBY.: $ cmake .. -DSYSINSTALL_PHP=ON Disabling Language Bindings --------------------------- To disable any given language bindings, you can use the BUILD_[LANGUAGE] option where [LANGUAGE] is one of JAVA, PERL, PHP, PYTHON or RUBY, e.g.: $ cmake .. -DBUILD_PHP=OFF Maven (All platforms) --------------------- The following prerequisites are required to do a full build. + Apache Maven 3.0 (or higher) (http://maven.apache.org/) From the directory where you found this README file: # To compile and package all Java modules (omitting the tests) $ mvn -DskipTests package # To install the packages in the local Maven repository (usually ~/.m2/repo) $ mvn -DskipTests install qpid-proton-0.14.0/NOTICE0000644000175000017500000000025412770711161014232 0ustar danieldanielApache Qpid Proton Copyright 2012-2016 The Apache Software Foundation This product includes software developed at The Apache Software Foundation (http://www.apache.org/). qpid-proton-0.14.0/RELEASE.md0000644000175000017500000000511512770711161014731 0ustar danieldaniel### Building a release for vote: 1. Grab a clean checkout for safety. 2. Run: "git checkout ${BRANCH}" to switch to a branch of the intended release point. 3. Update the versions: - Run: "bin/version.sh ${VERSION}", e.g. bin/release.sh 0.12.2. - Update the version if needed in file: proton-c/bindings/python/setuputils/bundle.py 4. Commit the changes, tag them. - Run: "git add ." - Run: 'git commit -m "update versions for ${TAG}"' - Run: 'git tag -m "tag $TAG" $TAG' - Push changes. Optionally save this bit for later. 5. Run: "bin/export.sh $PWD ${TAG}" to create the qpid-proton-${TAG}.tar.gz release archive. 6. Rename and create signature and checksums for the archive: - e.g "mv qpid-proton-${TAG}.tar.gz qpid-proton-${VERSION}.tar.gz" - e.g "gpg --detach-sign --armor qpid-proton-${VERSION}.tar.gz" - e.g "sha1sum qpid-proton-${VERSION}.tar.gz > qpid-proton-${VERSION}.tar.gz.sha1" - e.g "md5sum qpid-proton-${VERSION}.tar.gz > qpid-proton-${VERSION}.tar.gz.md5" 7. Deploy the Java binaries to a staging repo: - Run: "tar -xzf qpid-proton-${VERSION}.tar.gz" - Run: "cd qpid-proton-${VERSION}" - Run: "mvn deploy -Papache-release -DskipTests=true" 8. Close the staging repo: - Log in at https://repository.apache.org/index.html#stagingRepositories - Find the new 'open' staging repo just created and select its checkbox. - Click the 'close' button, provide a description, e.g "Proton ${TAG}" and close the repo. - Wait a few seconds, hit the 'refresh' button and confirm the repo is now 'closed'. - Click on the repo and find its URL listed in the summary. 9. Commit artifacts to dist dev repo in https://dist.apache.org/repos/dist/dev/qpid/proton/${TAG} dir. 10. Send email, provide links to dist dev repo and the staging repo. ### After a vote succeeds: 1. Bump the master/branch version to next 0.x.y-SNAPSHOT if it wasnt already. 2. Tag the RC with the final name/version. 3. Commit the artifacts to dist release repo in https://dist.apache.org/repos/dist/release/qpid/proton/${RELEASE} dir: - Rename the files to remove the RC suffix. - Fix filename within .sha and .md5 checksums or regenerate. 4. Update the 'latest' link in https://dist.apache.org/repos/dist/release/qpid/proton/. 5. Release the staging repo: - Log in at https://repository.apache.org/index.html#stagingRepositories - Find the 'closed' staging repo representing the RC select its checkbox. - Click the 'Release' button and release the repo. 6. Give the mirrors some time to distribute things. 7. Update the website with release content. 8. Update development roadmap. 9. Send release announcement email. qpid-proton-0.14.0/appveyor.yml0000644000175000017500000000067212770711161015722 0ustar danieldanielversion: '{branch}.{build}' configuration: RelWithDebInfo install: - cinst -y swig cache: - C:\ProgramData\chocolatey\bin -> appveyor.yml - C:\ProgramData\chocolatey\lib -> appveyor.yml before_build: - mkdir BLD - cd BLD - cmake -G "Visual Studio 12" -DBUILD_PERL=no .. - cd .. build: parallel: true verbosity: normal test_script: - cd BLD - cmake --build . --target install --config %CONFIGURATION% - ctest -V -C %CONFIGURATION% - cd .. qpid-proton-0.14.0/config.sh.in0000755000175000017500000000562112770711161015542 0ustar danieldaniel#!/bin/bash # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information # regarding copyright ownership. The ASF licenses this file # to you under the Apache License, Version 2.0 (the # "License"); you may not use this file except in compliance # with the License. You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, # software distributed under the License is distributed on an # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. # merge_paths() { # Merge paths, remove duplicates (keep first instance) path=$(echo $* | sed 's/:/ /'g) # Split with spaces. newpath="" for d in $path; do # Remove duplicates { echo $newpath | grep -q "\(:\|^\)$d\(:\|$\)"; } || newpath="$newpath:$d" done echo $newpath | sed 's/^://' # Remove leading : } PROTON_HOME=@CMAKE_SOURCE_DIR@ PROTON_BUILD=@CMAKE_BINARY_DIR@ PROTON_BINDINGS=$PROTON_BUILD/proton-c/bindings PROTON_JARS=$PROTON_BUILD/proton-j/proton-j.jar PYTHON_BINDINGS=$PROTON_BINDINGS/python PHP_BINDINGS=$PROTON_BINDINGS/php RUBY_BINDINGS=$PROTON_BINDINGS/ruby PERL_BINDINGS=$PROTON_BINDINGS/perl # Python & Jython COMMON_PYPATH=$PROTON_HOME/tests/python:$PROTON_HOME/proton-c/bindings/python export PYTHONPATH=$COMMON_PYPATH:$PYTHON_BINDINGS export JYTHONPATH=$COMMON_PYPATH:$PROTON_HOME/proton-j/src/main/resources:$PROTON_JARS export CLASSPATH=$PROTON_JARS # PHP if [ -d $PHP_BINDINGS ]; then cat < $PHP_BINDINGS/php.ini include_path="$PHP_BINDINGS:$PROTON_HOME/proton-c/bindings/php" extension="$PHP_BINDINGS/cproton.so" EOF export PHPRC=$PHP_BINDINGS/php.ini fi # Ruby export RUBYLIB=$RUBY_BINDINGS:$PROTON_HOME/proton-c/bindings/ruby/lib:$PROTON_HOME/tests/ruby # Perl export PERL5LIB=$PERL5LIB:$PERL_BINDINGS:$PROTON_HOME/proton-c/bindings/perl/lib # Go export GOPATH="$(merge_paths $PROTON_HOME/proton-c/bindings/go $GOPATH)" # Help Go compiler find libraries and include files. export C_INCLUDE_PATH="$(merge_paths $PROTON_HOME/proton-c/include $PROTON_BUILD/proton-c/include $C_INCLUDE_PATH)" export LIBRARY_PATH="$(merge_paths $PROTON_BUILD/proton-c $LIBRARY_PATH)" export LD_LIBRARY_PATH="$(merge_paths $PROTON_BUILD/proton-c $LD_LIBRARY_PATH)" # test applications export PATH="$(merge_paths $PATH $PROTON_BUILD/tests/tools/apps/c $PROTON_HOME/tests/tools/apps/python $PROTON_HOME/tests/python)" # can the test harness use valgrind? if [[ -x "$(type -p valgrind)" && "@ENABLE_VALGRIND@" == "ON" ]] ; then export VALGRIND=$(type -p valgrind) fi # can the test harness use saslpasswd2? if [[ -x "$(type -p saslpasswd2)" ]] ; then export SASLPASSWD=$(type -p saslpasswd2) fi qpid-proton-0.14.0/pom.xml0000644000175000017500000001353412770711161014650 0ustar danieldaniel Proton is a library for speaking AMQP. org.apache apache 12 4.0.0 org.apache.qpid proton-project 0.14.0 pom 4.12 1.10.19 1.3 2.2.1 2.5.4 proton-site-id file:///tmp/proton-site org.apache.maven.plugins maven-compiler-plugin 1.7 1.7 true true true org.apache.maven.plugins maven-site-plugin org.apache.maven.doxia doxia-module-markdown ${doxia-module-version} UTF-8 UTF-8 docs org.apache.felix maven-bundle-plugin ${maven-bundle-plugin-version} true ${project.groupId}.proton.* org.eclipse.m2e lifecycle-mapping 1.0.0 org.apache.felix maven-bundle-plugin [2.4.0,) manifest junit junit ${junit-version} test org.mockito mockito-core ${mockito-version} test proton-j tests examples/engine/java examples/java/messenger examples/java/reactor http://qpid.apache.org/proton http://svn.apache.org/viewvc/qpid/proton/ https://issues.apache.org/jira/browse/PROTON https://builds.apache.org/view/M-R/view/Qpid/job/Qpid-proton-j/ sources org.apache.maven.plugins maven-source-plugin ${maven-source-plugin-version} attach-sources jar qpid-proton-0.14.0/qpid-proton-cpp.syms0000644000175000017500000006265112770711161017310 0ustar danieldaniel# XXX acceptor symbols, but not connector? proton::acceptor::close() proton::acceptor::connection_options() proton::condition::description() const proton::condition::empty() const proton::condition::info() const proton::condition::name() const proton::condition::operator!() const proton::condition::what() const proton::connection::close() proton::connection::container() const proton::connection::container_id() const proton::connection::default_session() proton::connection::host(std::string const&) proton::connection::host() const proton::connection::links() const proton::connection::local_condition() const proton::connection::open() proton::connection::open_receiver(std::string const&, proton::link_options const&) proton::connection::open_sender(std::string const&, proton::link_options const&) proton::connection::open_session() proton::connection::password(std::string const&) proton::connection::release() proton::connection::remote_condition() const proton::connection::sessions() const proton::connection::state() const proton::connection::transport() const proton::connection::user(std::string const&) proton::connection::~connection() proton::connection_engine::can_read() const proton::connection_engine::can_write() const proton::connection_engine::closed() const proton::connection_engine::connection() const proton::connection_engine::connection_engine(proton::handler&, proton::connection_options const&) proton::connection_engine::container::container(std::string const&) proton::connection_engine::container::id() const proton::connection_engine::container::make_options() proton::connection_engine::container::options(proton::connection_options const&) proton::connection_engine::container::~container() proton::connection_engine::dispatch() proton::connection_engine::io_error::io_error(std::string const&) proton::connection_engine::io_error::~io_error() proton::connection_engine::no_opts proton::connection_engine::process(int) proton::connection_engine::try_read() proton::connection_engine::try_write() proton::connection_engine::~connection_engine() proton::connection_options::connection_options() proton::connection_options::connection_options(proton::connection_options const&) proton::connection_options::container_id(std::string const&) proton::connection_options::handler(proton::handler*) proton::connection_options::heartbeat(proton::duration) proton::connection_options::idle_timeout(proton::duration) proton::connection_options::link_prefix(std::string const&) proton::connection_options::max_channels(unsigned short) proton::connection_options::max_frame_size(unsigned int) proton::connection_options::operator=(proton::connection_options const&) proton::connection_options::override(proton::connection_options const&) proton::connection_options::reconnect(proton::reconnect_timer const&) proton::connection_options::sasl_allow_insecure_mechs(bool) proton::connection_options::sasl_allowed_mechs(std::string const&) proton::connection_options::sasl_config_name(std::string const&) proton::connection_options::sasl_config_path(std::string const&) proton::connection_options::sasl_enabled(bool) proton::connection_options::ssl_client_options(proton::ssl_client_options const&) proton::connection_options::ssl_server_options(proton::ssl_server_options const&) proton::connection_options::~connection_options() proton::container::client_connection_options(proton::connection_options const&) proton::container::connect(proton::url const&, proton::connection_options const&) proton::container::container(proton::handler&, std::string const&) proton::container::container(std::string const&) proton::container::id() const proton::container::listen(proton::url const&, proton::connection_options const&) proton::container::open_receiver(proton::url const&, proton::link_options const&, proton::connection_options const&) proton::container::open_sender(proton::url const&, proton::link_options const&, proton::connection_options const&) proton::container::run() proton::container::schedule(int, proton::handler*) proton::container::server_connection_options(proton::connection_options const&) proton::container::~container() proton::conversion_error::conversion_error(std::string const&) proton::conversion_error::~conversion_error() proton::delivery::clear() proton::delivery::link() const proton::delivery::partial() const proton::delivery::pending() const proton::delivery::readable() const proton::delivery::remote_state() const proton::delivery::settle() proton::delivery::settle(proton::delivery::state) proton::delivery::settled() const proton::delivery::update(proton::delivery::state) proton::delivery::updated() const proton::delivery::writable() const proton::duration::FOREVER proton::duration::IMMEDIATE proton::duration::MINUTE proton::duration::SECOND proton::endpoint::LOCAL_ACTIVE proton::endpoint::LOCAL_CLOSED proton::endpoint::LOCAL_MASK proton::endpoint::LOCAL_UNINIT proton::endpoint::REMOTE_ACTIVE proton::endpoint::REMOTE_CLOSED proton::endpoint::REMOTE_MASK proton::endpoint::REMOTE_UNINIT proton::endpoint::~endpoint() proton::error::error(std::string const&) proton::error::~error() proton::handler::handler(int, bool, bool, bool) # XXX Do these default implementations actually need to be exported? # The API user never uses them directly he only overrides virtuals proton::handler::on_connection_close(proton::event&) proton::handler::on_connection_error(proton::event&) proton::handler::on_connection_open(proton::event&) proton::handler::on_delivery_accept(proton::event&) proton::handler::on_delivery_reject(proton::event&) proton::handler::on_delivery_release(proton::event&) proton::handler::on_delivery_settle(proton::event&) proton::handler::on_link_close(proton::event&) proton::handler::on_link_error(proton::event&) proton::handler::on_link_open(proton::event&) proton::handler::on_message(proton::event&) proton::handler::on_sendable(proton::event&) proton::handler::on_session_close(proton::event&) proton::handler::on_session_error(proton::event&) proton::handler::on_session_open(proton::event&) proton::handler::on_start(proton::event&) proton::handler::on_timer(proton::event&) proton::handler::on_transport_close(proton::event&) proton::handler::on_transport_error(proton::event&) proton::handler::on_unhandled(proton::event&) proton::handler::on_unhandled_error(proton::event&, proton::condition const&) proton::handler::~handler() # XXX I wonder how much of these internal symbols can just not be exported proton::internal::assert_map_scope(proton::internal::scope const&) proton::internal::data::append(proton::internal::data) proton::internal::data::appendn(proton::internal::data, int) proton::internal::data::clear() proton::internal::data::copy(proton::internal::data const&) proton::internal::data::create() proton::internal::data::decoder() proton::internal::data::empty() const proton::internal::data::encoder() proton::internal::data::equal(proton::internal::data const&) const proton::internal::data::less(proton::internal::data const&) const proton::internal::data::narrow() proton::internal::data::next() const proton::internal::data::point() const proton::internal::data::restore(unsigned long) proton::internal::data::type() const proton::internal::data::widen() proton::internal::decoder::backup() proton::internal::decoder::check_type(proton::type_id) proton::internal::decoder::decode(char const*, unsigned long) proton::internal::decoder::decode(std::string const&) proton::internal::decoder::more() const proton::internal::decoder::operator>>(bool&) proton::internal::decoder::operator>>(double&) proton::internal::decoder::operator>>(float&) proton::internal::decoder::operator>>(int&) proton::internal::decoder::operator>>(long&) proton::internal::decoder::operator>>(proton::annotation_key&) proton::internal::decoder::operator>>(proton::decimal128&) proton::internal::decoder::operator>>(proton::decimal32&) proton::internal::decoder::operator>>(proton::decimal64&) proton::internal::decoder::operator>>(proton::internal::assert_type) proton::internal::decoder::operator>>(proton::internal::finish) proton::internal::decoder::operator>>(proton::internal::rewind) proton::internal::decoder::operator>>(proton::internal::skip) proton::internal::decoder::operator>>(proton::internal::start&) proton::internal::decoder::operator>>(proton::message_id&) proton::internal::decoder::operator>>(proton::scalar&) proton::internal::decoder::operator>>(proton::timestamp&) proton::internal::decoder::operator>>(proton::uuid&) proton::internal::decoder::operator>>(proton::value&) proton::internal::decoder::operator>>(short&) proton::internal::decoder::operator>>(signed char&) proton::internal::decoder::operator>>(std::string&) proton::internal::decoder::operator>>(unsigned char&) proton::internal::decoder::operator>>(unsigned int&) proton::internal::decoder::operator>>(unsigned long&) proton::internal::decoder::operator>>(unsigned short&) proton::internal::decoder::operator>>(wchar_t&) proton::internal::decoder::rewind() proton::internal::decoder::skip() proton::internal::decoder::type() const proton::internal::encoder::encode(char*, unsigned long&) proton::internal::encoder::encode(std::string&) proton::internal::encoder::encode() proton::internal::encoder::insert(proton::value const&) proton::internal::encoder::operator<<(bool) proton::internal::encoder::operator<<(double) proton::internal::encoder::operator<<(float) proton::internal::encoder::operator<<(int) proton::internal::encoder::operator<<(long) proton::internal::encoder::operator<<(proton::binary const&) proton::internal::encoder::operator<<(proton::decimal128) proton::internal::encoder::operator<<(proton::decimal32) proton::internal::encoder::operator<<(proton::decimal64) proton::internal::encoder::operator<<(proton::internal::finish const&) proton::internal::encoder::operator<<(proton::internal::start const&) proton::internal::encoder::operator<<(proton::scalar const&) proton::internal::encoder::operator<<(proton::symbol const&) proton::internal::encoder::operator<<(proton::timestamp) proton::internal::encoder::operator<<(proton::uuid const&) proton::internal::encoder::operator<<(short) proton::internal::encoder::operator<<(signed char) proton::internal::encoder::operator<<(std::string const&) proton::internal::encoder::operator<<(unsigned char) proton::internal::encoder::operator<<(unsigned int) proton::internal::encoder::operator<<(unsigned long) proton::internal::encoder::operator<<(unsigned short) proton::internal::encoder::operator<<(wchar_t) proton::internal::operator<<(std::ostream&, proton::internal::data const&) proton::internal::operator<<(std::ostream&, proton::internal::encoder const&) proton::internal::pn_ptr_base::decref(void*) proton::internal::pn_ptr_base::incref(void*) proton::internal::ssl_domain::operator=(proton::internal::ssl_domain const&) proton::internal::ssl_domain::ssl_domain(proton::internal::ssl_domain const&) proton::internal::ssl_domain::~ssl_domain() proton::internal::start::array(proton::type_id, bool) proton::internal::start::described() proton::internal::start::list() proton::internal::start::map() proton::internal::start::start(proton::type_id, proton::type_id, bool, unsigned long) # XXX Not sure how much of this should be exposed proton::io::INVALID_DESCRIPTOR proton::io::connect(proton::url const&) proton::io::error_str() proton::io::finalize() proton::io::initialize() proton::io::listener::accept(std::string&, std::string&) proton::io::listener::listener(std::string const&, std::string const&) proton::io::listener::~listener() proton::io::socket_engine::io_close() proton::io::socket_engine::io_read(char*, unsigned long) proton::io::socket_engine::io_write(char const*, unsigned long) proton::io::socket_engine::run() proton::io::socket_engine::socket_engine(long, proton::handler&, proton::connection_options const&) proton::io::socket_engine::socket_engine(proton::url const&, proton::handler&, proton::connection_options const&) proton::io::socket_engine::~socket_engine() proton::link::advance() proton::link::close() proton::link::connection() const proton::link::credit() const proton::link::detach() proton::link::detach_handler() proton::link::drained() proton::link::handler(proton::proton_handler&) proton::link::local_condition() const proton::link::local_source() const proton::link::local_target() const proton::link::name() const proton::link::open(proton::link_options const&) proton::link::queued() proton::link::receiver() proton::link::receiver() const proton::link::receiver_settle_mode() proton::link::receiver_settle_mode(proton::link_options::receiver_settle_mode) proton::link::recv(char*, unsigned long) proton::link::remote_condition() const proton::link::remote_receiver_settle_mode() proton::link::remote_sender_settle_mode() proton::link::remote_source() const proton::link::remote_target() const proton::link::sender() proton::link::sender() const proton::link::sender_settle_mode() proton::link::sender_settle_mode(proton::link_options::sender_settle_mode) proton::link::session() const proton::link::state() const proton::link::unsettled() proton::link::~link() proton::link_iterator::operator++() proton::link_options::browsing(bool) proton::link_options::delivery_mode(proton::link_options::delivery_mode) proton::link_options::distribution_mode(proton::terminus::distribution_mode) proton::link_options::durable_subscription(bool) proton::link_options::dynamic_address(bool) proton::link_options::handler(proton::handler*) proton::link_options::lifetime_policy(proton::link_options::lifetime_policy) proton::link_options::link_options() proton::link_options::link_options(proton::link_options const&) proton::link_options::local_address(std::string const&) proton::link_options::operator=(proton::link_options const&) proton::link_options::override(proton::link_options const&) proton::link_options::selector(std::string const&) proton::link_options::~link_options() proton::message::address(std::string const&) proton::message::address() const proton::message::application_properties() proton::message::application_properties() const proton::message::body() proton::message::body() const proton::message::clear() proton::message::content_encoding(std::string const&) proton::message::content_encoding() const proton::message::content_type(std::string const&) proton::message::content_type() const proton::message::correlation_id() const proton::message::correlation_id(proton::message_id const&) proton::message::creation_time() const proton::message::creation_time(proton::timestamp) proton::message::decode(std::vector > const&) proton::message::delivery_annotations() proton::message::delivery_annotations() const proton::message::delivery_count() const proton::message::delivery_count(unsigned int) proton::message::durable() const proton::message::durable(bool) proton::message::encode() const proton::message::encode(std::vector >&) const proton::message::expiry_time() const proton::message::expiry_time(proton::timestamp) proton::message::first_acquirer() const proton::message::first_acquirer(bool) proton::message::group_id(std::string const&) proton::message::group_id() const proton::message::group_sequence() const proton::message::group_sequence(int) proton::message::id() const proton::message::id(proton::message_id const&) proton::message::inferred() const proton::message::inferred(bool) proton::message::message() proton::message::message(proton::message const&) proton::message::message_annotations() proton::message::message_annotations() const proton::message::operator=(proton::message const&) proton::message::priority() const proton::message::priority(unsigned char) proton::message::reply_to(std::string const&) proton::message::reply_to() const proton::message::reply_to_group_id(std::string const&) proton::message::reply_to_group_id() const proton::message::subject(std::string const&) proton::message::subject() const proton::message::ttl() const proton::message::ttl(proton::duration) proton::message::user_id(std::string const&) proton::message::user_id() const proton::message::~message() proton::operator<(proton::scalar const&, proton::scalar const&) proton::operator<(proton::value const&, proton::value const&) proton::operator<<(std::ostream&, proton::decimal128 const&) proton::operator<<(std::ostream&, proton::decimal32 const&) proton::operator<<(std::ostream&, proton::decimal64 const&) proton::operator<<(std::ostream&, proton::duration) proton::operator<<(std::ostream&, proton::scalar const&) proton::operator<<(std::ostream&, proton::timestamp) proton::operator<<(std::ostream&, proton::type_id) proton::operator<<(std::ostream&, proton::url const&) proton::operator<<(std::ostream&, proton::uuid const&) proton::operator<<(std::ostream&, proton::value const&) proton::operator==(proton::scalar const&, proton::scalar const&) proton::operator==(proton::value const&, proton::value const&) proton::operator>>(std::istream&, proton::url&) proton::receiver::flow(int) proton::receiver::~receiver() proton::reconnect_timer::next_delay(proton::timestamp) proton::reconnect_timer::reconnect_timer(unsigned int, int, unsigned int, bool, int, int) proton::reconnect_timer::reset() proton::sasl::allow_insecure_mechs() proton::sasl::allow_insecure_mechs(bool) proton::sasl::allowed_mechs(std::string const&) proton::sasl::config_name(std::string const&) proton::sasl::config_path(std::string const&) proton::sasl::done(proton::sasl::outcome) proton::sasl::extended() proton::sasl::mech() const proton::sasl::outcome() const proton::sasl::user() const proton::scalar::as_double() const proton::scalar::as_int() const proton::scalar::as_string() const proton::scalar::as_uint() const proton::scalar::empty() const proton::scalar::get(bool&) const proton::scalar::get(double&) const proton::scalar::get(float&) const proton::scalar::get(int&) const proton::scalar::get(long&) const proton::scalar::get(proton::binary&) const proton::scalar::get(proton::decimal128&) const proton::scalar::get(proton::decimal32&) const proton::scalar::get(proton::decimal64&) const proton::scalar::get(proton::symbol&) const proton::scalar::get(proton::timestamp&) const proton::scalar::get(proton::uuid&) const proton::scalar::get(short&) const proton::scalar::get(signed char&) const proton::scalar::get(std::string&) const proton::scalar::get(unsigned char&) const proton::scalar::get(unsigned int&) const proton::scalar::get(unsigned long&) const proton::scalar::get(unsigned short&) const proton::scalar::get(wchar_t&) const proton::scalar::operator=(bool) proton::scalar::operator=(char const*) proton::scalar::operator=(double) proton::scalar::operator=(float) proton::scalar::operator=(int) proton::scalar::operator=(long) proton::scalar::operator=(proton::binary const&) proton::scalar::operator=(proton::decimal128 const&) proton::scalar::operator=(proton::decimal32 const&) proton::scalar::operator=(proton::decimal64 const&) proton::scalar::operator=(proton::scalar const&) proton::scalar::operator=(proton::symbol const&) proton::scalar::operator=(proton::timestamp) proton::scalar::operator=(proton::uuid const&) proton::scalar::operator=(short) proton::scalar::operator=(signed char) proton::scalar::operator=(std::string const&) proton::scalar::operator=(unsigned char) proton::scalar::operator=(unsigned int) proton::scalar::operator=(unsigned long) proton::scalar::operator=(unsigned short) proton::scalar::operator=(wchar_t) proton::scalar::scalar() proton::scalar::scalar(proton::scalar const&) proton::scalar::type() const proton::sender::available() proton::sender::offered(int) proton::sender::send(proton::message const&) proton::sender::~sender() proton::session::connection() const proton::session::create_receiver(std::string const&) proton::session::create_sender(std::string const&) proton::session::links() const proton::session::local_condition() const proton::session::open() proton::session::open_receiver(std::string const&, proton::link_options const&) proton::session::open_sender(std::string const&, proton::link_options const&) proton::session::remote_condition() const proton::session::state() const proton::session::~session() proton::session_iterator::operator++() proton::ssl::cipher() const proton::ssl::peer_hostname(std::string const&) proton::ssl::peer_hostname() const proton::ssl::protocol() const proton::ssl::remote_subject() const proton::ssl::resume_status() const proton::ssl::ssf() const proton::ssl_certificate::ssl_certificate(std::string const&, std::string const&) proton::ssl_certificate::ssl_certificate(std::string const&, std::string const&, std::string const&) proton::ssl_client_options::ssl_client_options() proton::ssl_client_options::ssl_client_options(proton::ssl_certificate&, std::string const&, proton::ssl::verify_mode) proton::ssl_client_options::ssl_client_options(std::string const&, proton::ssl::verify_mode) proton::ssl_server_options::ssl_server_options() proton::ssl_server_options::ssl_server_options(proton::ssl_certificate&) proton::ssl_server_options::ssl_server_options(proton::ssl_certificate&, std::string const&, std::string const&, proton::ssl::verify_mode) proton::swap(proton::message&, proton::message&) proton::swap(proton::value&, proton::value&) proton::task::cancel() proton::terminus::address(std::string const&) proton::terminus::address() const proton::terminus::distribution_mode() const proton::terminus::distribution_mode(proton::terminus::distribution_mode) proton::terminus::durability() proton::terminus::durability(proton::terminus::durability) proton::terminus::dynamic() const proton::terminus::dynamic(bool) proton::terminus::expiry_policy() const proton::terminus::expiry_policy(proton::terminus::expiry_policy) proton::terminus::filter() proton::terminus::filter() const proton::terminus::node_properties() proton::terminus::node_properties() const proton::terminus::timeout() const proton::terminus::timeout(unsigned int) proton::terminus::type() const proton::terminus::type(proton::terminus::type) proton::timeout_error::timeout_error(std::string const&) proton::timeout_error::~timeout_error() proton::timestamp::now() proton::transport::bind(proton::connection&) proton::transport::condition() const proton::transport::connection() const proton::transport::idle_timeout() const proton::transport::max_channels() const proton::transport::max_frame_size() const proton::transport::remote_idle_timeout() const proton::transport::remote_max_channels() const proton::transport::remote_max_frame_size() const proton::transport::sasl() const proton::transport::ssl() const proton::transport::unbind() proton::type_id_is_container(proton::type_id) proton::type_id_is_decimal(proton::type_id) proton::type_id_is_floating_point(proton::type_id) proton::type_id_is_integral(proton::type_id) proton::type_id_is_scalar(proton::type_id) proton::type_id_is_signed(proton::type_id) proton::type_id_is_signed_int(proton::type_id) proton::type_id_is_string_like(proton::type_id) proton::type_id_is_unsigned_int(proton::type_id) # XXX Why is this a free function not a member function? proton::type_name(proton::type_id) proton::url::defaults() proton::url::empty() const proton::url::host(std::string const&) proton::url::host() const proton::url::host_port() const proton::url::operator=(proton::url const&) proton::url::parse(char const*) proton::url::parse(std::string const&) proton::url::password(std::string const&) proton::url::password() const proton::url::path(std::string const&) proton::url::path() const proton::url::port(std::string const&) proton::url::port() const proton::url::port_int() const proton::url::scheme(std::string const&) proton::url::scheme() const proton::url::str() const proton::url::url() proton::url::url(char const*, bool) proton::url::url(proton::url const&) proton::url::url(std::string const&, bool) proton::url::username(std::string const&) proton::url::username() const proton::url::~url() proton::url_error::url_error(std::string const&) proton::url_error::~url_error() proton::uuid::make(char const*) proton::uuid::random() proton::uuid::str() const proton::value::as_double() const proton::value::as_int() const proton::value::as_string() const proton::value::as_uint() const proton::value::clear() proton::value::decode() const proton::value::empty() const proton::value::encode() proton::value::operator=(proton::value const&) proton::value::type() const proton::value::value() proton::value::value(pn_data_t*) proton::value::value(proton::value const&) # Only types with the following info can be thrown across shared abject boundary # Or correctly dynamically cast by user typeinfo for proton::connection typeinfo for proton::connection_engine typeinfo for proton::connection_engine::io_error typeinfo for proton::conversion_error typeinfo for proton::endpoint typeinfo for proton::error typeinfo for proton::handler typeinfo for proton::link typeinfo for proton::receiver typeinfo for proton::sender typeinfo for proton::session typeinfo for proton::timeout_error typeinfo for proton::url_error typeinfo name for proton::connection typeinfo name for proton::connection_engine typeinfo name for proton::connection_engine::io_error typeinfo name for proton::conversion_error typeinfo name for proton::endpoint typeinfo name for proton::error typeinfo name for proton::handler typeinfo name for proton::link typeinfo name for proton::receiver typeinfo name for proton::sender typeinfo name for proton::session typeinfo name for proton::timeout_error typeinfo name for proton::url_error vtable for proton::connection vtable for proton::connection_engine vtable for proton::connection_engine::io_error vtable for proton::conversion_error vtable for proton::endpoint vtable for proton::error vtable for proton::handler vtable for proton::link vtable for proton::receiver vtable for proton::sender vtable for proton::session vtable for proton::timeout_error vtable for proton::url_error qpid-proton-0.14.0/version.txt0000644000175000017500000000000712770711161015550 0ustar danieldaniel0.14.0