diff options
author | Kim van der Riet <kpvdr@apache.org> | 2013-02-28 16:14:30 +0000 |
---|---|---|
committer | Kim van der Riet <kpvdr@apache.org> | 2013-02-28 16:14:30 +0000 |
commit | 9c73ef7a5ac10acd6a50d5d52bd721fc2faa5919 (patch) | |
tree | 2a890e1df09e5b896a9b4168a7b22648f559a1f2 /cpp/bindings | |
parent | 172d9b2a16cfb817bbe632d050acba7e31401cd2 (diff) | |
download | qpid-python-asyncstore.tar.gz |
Update from trunk r1375509 through r1450773asyncstore
git-svn-id: https://svn.apache.org/repos/asf/qpid/branches/asyncstore@1451244 13f79535-47bb-0310-9956-ffa450edef68
Diffstat (limited to 'cpp/bindings')
105 files changed, 4762 insertions, 2592 deletions
diff --git a/cpp/bindings/CMakeLists.txt b/cpp/bindings/CMakeLists.txt new file mode 100644 index 0000000000..3d44ef01cd --- /dev/null +++ b/cpp/bindings/CMakeLists.txt @@ -0,0 +1,67 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + + +include(FindSWIG) +include(UseSWIG) +include(FindRuby) +include(FindPythonLibs) +include(FindPerlLibs) + +set (SWIG_MINIMUM_VERSION "1.3.32") + +if (SWIG_FOUND) + if (${SWIG_VERSION} VERSION_LESS ${SWIG_MINIMUM_VERSION}) + message("Found Swig < ${SWIG_MINIMUM_VERSION} - skipping language bindings") + else() + set(CMAKE_SWIG_FLAGS "-w361,362,401,467,503") + + if (PYTHONLIBS_FOUND) + execute_process(COMMAND ${PYTHON_EXECUTABLE} + -c "from distutils.sysconfig import get_python_lib; print get_python_lib(True, prefix='${CMAKE_INSTALL_PREFIX}')" + OUTPUT_VARIABLE PYTHON_SITEARCH_PACKAGES + OUTPUT_STRIP_TRAILING_WHITESPACE) + + add_subdirectory(qpid/python) + add_subdirectory(qmf2/python) + add_subdirectory(qmf/python) + endif (PYTHONLIBS_FOUND) + + if (RUBY_FOUND) + execute_process(COMMAND ${RUBY_EXECUTABLE} -r rbconfig -e "puts RbConfig::CONFIG['prefix']" + OUTPUT_VARIABLE RUBY_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REPLACE ${RUBY_PREFIX} ${CMAKE_INSTALL_PREFIX} RUBY_PFX_ARCH_DIR ${RUBY_ARCH_DIR}) + + add_subdirectory(qpid/ruby) + add_subdirectory(qmf2/ruby) + add_subdirectory(qmf/ruby) + endif (RUBY_FOUND) + + if (PERLLIBS_FOUND) + execute_process(COMMAND ${PERL_EXECUTABLE} "-V::prefix:" + OUTPUT_VARIABLE QPERL_PREFIX + OUTPUT_STRIP_TRAILING_WHITESPACE) + string(REGEX REPLACE "'(.*)'" "\\1" PERL_PREFIX ${QPERL_PREFIX}) + string(REPLACE ${PERL_PREFIX} ${CMAKE_INSTALL_PREFIX} PERL_PFX_ARCHLIB ${PERL_ARCHLIB}) + + add_subdirectory(qpid/perl) + endif (PERLLIBS_FOUND) + endif (${SWIG_VERSION} VERSION_LESS ${SWIG_MINIMUM_VERSION}) +endif (SWIG_FOUND) diff --git a/cpp/bindings/qmf/CMakeLists.txt b/cpp/bindings/qmf/CMakeLists.txt deleted file mode 100644 index 5e40539e80..0000000000 --- a/cpp/bindings/qmf/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -include(FindSWIG) -include(UseSWIG) -include(FindRuby) -include(FindPythonLibs) -include(FindPerlLibs) - -if (SWIG_FOUND) - set(CMAKE_SWIG_FLAGS "-w362,401") - - if (PYTHONLIBS_FOUND) - add_subdirectory(python) - endif (PYTHONLIBS_FOUND) - - if (RUBY_FOUND) - add_subdirectory(ruby) - endif (RUBY_FOUND) -endif (SWIG_FOUND) diff --git a/cpp/bindings/qmf/Makefile.am b/cpp/bindings/qmf/Makefile.am index dd77ab080c..ee4ff1d3c1 100644 --- a/cpp/bindings/qmf/Makefile.am +++ b/cpp/bindings/qmf/Makefile.am @@ -19,7 +19,6 @@ if HAVE_SWIG -EXTRA_DIST = CMakeLists.txt qmfengine.i SUBDIRS = tests if HAVE_RUBY_DEVEL diff --git a/cpp/bindings/qmf/python/CMakeLists.txt b/cpp/bindings/qmf/python/CMakeLists.txt index 9bc6b2e878..1768df7f85 100644 --- a/cpp/bindings/qmf/python/CMakeLists.txt +++ b/cpp/bindings/qmf/python/CMakeLists.txt @@ -21,7 +21,7 @@ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") swig_add_module(qmfengine_python python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) swig_link_libraries(qmfengine_python qmf qmfconsole ${PYTHON_LIBRARIES}) @@ -31,28 +31,23 @@ set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_F ##------------------------------------ ## Install the complete Python binding ##------------------------------------ -execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile qmfengine.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile qmfengine.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/qmf.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile qmf.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile qmf.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qmfengine.py - ${CMAKE_CURRENT_BINARY_DIR}/qmfengine.pyc - ${CMAKE_CURRENT_BINARY_DIR}/qmfengine.pyo ${CMAKE_CURRENT_SOURCE_DIR}/qmf.py - ${CMAKE_CURRENT_BINARY_DIR}/qmf.pyc - ${CMAKE_CURRENT_BINARY_DIR}/qmf.pyo - DESTINATION ${PYTHON_SITE_PACKAGES} + DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/_qmfengine_python.so RENAME _qmfengine.so - DESTINATION ${PYTHON_SITE_PACKAGES} + DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) +# Python compile the installed modules +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile qmfengine.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile qmfengine.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile qmf.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile qmf.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") diff --git a/cpp/bindings/qmf/python/Makefile.am b/cpp/bindings/qmf/python/Makefile.am index bcef8c6b53..07f3c1072b 100644 --- a/cpp/bindings/qmf/python/Makefile.am +++ b/cpp/bindings/qmf/python/Makefile.am @@ -29,7 +29,7 @@ EXTRA_DIST = CMakeLists.txt python.i BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 -$(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmfengine.i +$(generated_file_list): $(srcdir)/python.i $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o qmfengine.cpp $(srcdir)/python.i pylibdir = $(pyexecdir) diff --git a/cpp/bindings/qmf/python/python.i b/cpp/bindings/qmf/python/python.i index 5e25d155f9..118d0d3dbd 100644 --- a/cpp/bindings/qmf/python/python.i +++ b/cpp/bindings/qmf/python/python.i @@ -139,5 +139,5 @@ -%include "../qmfengine.i" +%include "qmf/qmfengine.i" diff --git a/cpp/bindings/qmf/qmfengine.i b/cpp/bindings/qmf/qmfengine.i deleted file mode 100644 index eb350115a3..0000000000 --- a/cpp/bindings/qmf/qmfengine.i +++ /dev/null @@ -1,59 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%{ - -#include "qmf/engine/Agent.h" -#include "qmf/engine/Console.h" -#include "qmf/engine/ResilientConnection.h" - -%} - -%include <qmf/engine/QmfEngineImportExport.h> -%include <qmf/engine/Query.h> -%include <qmf/engine/Message.h> -%include <qmf/engine/Agent.h> -%include <qmf/engine/Console.h> -%include <qmf/engine/ConnectionSettings.h> -%include <qmf/engine/ResilientConnection.h> -%include <qmf/engine/Typecode.h> -%include <qmf/engine/Schema.h> -%include <qmf/engine/Value.h> -%include <qmf/engine/ObjectId.h> -%include <qmf/engine/Object.h> -%include <qmf/engine/Event.h> - - -%inline { - -using namespace std; -using namespace qmf::engine; - -namespace qmf { -namespace engine { - -} -} -} - - -%{ - -%}; - diff --git a/cpp/bindings/qmf/ruby/CMakeLists.txt b/cpp/bindings/qmf/ruby/CMakeLists.txt index 702606139b..1fb2542e46 100644 --- a/cpp/bindings/qmf/ruby/CMakeLists.txt +++ b/cpp/bindings/qmf/ruby/CMakeLists.txt @@ -22,7 +22,9 @@ ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) -include_directories(${RUBY_INCLUDE_DIRS} ${qpid-cpp_SOURCE_DIR}/include) +include_directories(${RUBY_INCLUDE_DIRS} + ${qpid-cpp_SOURCE_DIR}/include + ${qpid-cpp_SOURCE_DIR}/bindings) swig_add_module(qmfengine_ruby ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) swig_link_libraries(qmfengine_ruby qmf qmfconsole ${RUBY_LIBRARY}) @@ -32,6 +34,6 @@ swig_link_libraries(qmfengine_ruby qmf qmfconsole ${RUBY_LIBRARY}) ##---------------------------------- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libqmfengine_ruby.so RENAME qmfengine.so - DESTINATION ${RUBY_ARCH_DIR} + DESTINATION ${RUBY_PFX_ARCH_DIR} COMPONENT ${QPID_COMPONENT_CLIENT} ) diff --git a/cpp/bindings/qmf/ruby/Makefile.am b/cpp/bindings/qmf/ruby/Makefile.am index 1c7f67edb3..33393aeda0 100644 --- a/cpp/bindings/qmf/ruby/Makefile.am +++ b/cpp/bindings/qmf/ruby/Makefile.am @@ -29,7 +29,7 @@ rubylibdir = $(RUBY_LIB) dist_rubylib_DATA = qmf.rb -qmfengine.cpp: $(srcdir)/ruby.i $(srcdir)/../qmfengine.i +qmfengine.cpp: $(srcdir)/ruby.i $(SWIG) -ruby -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o qmfengine.cpp $(srcdir)/ruby.i rubylibarchdir = $(RUBY_LIB_ARCH) diff --git a/cpp/bindings/qmf/ruby/qmf.rb b/cpp/bindings/qmf/ruby/qmf.rb index 9fbd50cbf6..d05127db4b 100644 --- a/cpp/bindings/qmf/ruby/qmf.rb +++ b/cpp/bindings/qmf/ruby/qmf.rb @@ -319,9 +319,7 @@ module Qmf eventImpl.sessionContext.handler.sess_event_recv(eventImpl.sessionContext, eventImpl.message) end rescue Exception => ex - puts "Event Exception: #{ex}" if bt_count < 2 - puts ex.backtrace bt_count += 1 end end @@ -1251,9 +1249,7 @@ module Qmf when Qmfengine::ConsoleEvent::METHOD_RESPONSE end rescue Exception => ex - puts "Exception caught in callback: #{ex}" if @bt_count < 2 - puts ex.backtrace @bt_count += 1 end end @@ -1381,14 +1377,13 @@ module Qmf end def conn_event_connected() - puts "Console Connection Established..." @session = Session.new(@conn, "qmfc-%s.%d" % [Socket.gethostname, Process::pid], self) @impl.sessionOpened(@session.handle) do_events end def conn_event_disconnected(error) - puts "Console Connection Lost" + end def conn_event_visit @@ -1396,12 +1391,10 @@ module Qmf end def sess_event_session_closed(context, error) - puts "Console Session Lost" @impl.sessionClosed() end def sess_event_recv(context, message) - puts "Unexpected RECV Event" if not @operational @impl.handleRcvMessage(message) do_events end @@ -1510,14 +1503,13 @@ module Qmf end def conn_event_connected() - puts "Agent Connection Established..." @session = Session.new(@conn, "qmfa-%s.%d" % [Socket.gethostname, Process::pid], self) @impl.newSession do_events end def conn_event_disconnected(error) - puts "Agent Connection Lost" + end def conn_event_visit @@ -1525,7 +1517,7 @@ module Qmf end def sess_event_session_closed(context, error) - puts "Agent Session Lost" + end def sess_event_recv(context, message) diff --git a/cpp/bindings/qmf/ruby/ruby.i b/cpp/bindings/qmf/ruby/ruby.i index 0101861100..2854aa0c7e 100644 --- a/cpp/bindings/qmf/ruby/ruby.i +++ b/cpp/bindings/qmf/ruby/ruby.i @@ -102,5 +102,5 @@ } -%include "../qmfengine.i" +%include "qmf/qmfengine.i" diff --git a/cpp/bindings/qmf2/CMakeLists.txt b/cpp/bindings/qmf2/CMakeLists.txt deleted file mode 100644 index 5e40539e80..0000000000 --- a/cpp/bindings/qmf2/CMakeLists.txt +++ /dev/null @@ -1,37 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -include(FindSWIG) -include(UseSWIG) -include(FindRuby) -include(FindPythonLibs) -include(FindPerlLibs) - -if (SWIG_FOUND) - set(CMAKE_SWIG_FLAGS "-w362,401") - - if (PYTHONLIBS_FOUND) - add_subdirectory(python) - endif (PYTHONLIBS_FOUND) - - if (RUBY_FOUND) - add_subdirectory(ruby) - endif (RUBY_FOUND) -endif (SWIG_FOUND) diff --git a/cpp/bindings/qmf2/Makefile.am b/cpp/bindings/qmf2/Makefile.am index 9a03a5cd21..0f50e757a2 100644 --- a/cpp/bindings/qmf2/Makefile.am +++ b/cpp/bindings/qmf2/Makefile.am @@ -19,7 +19,6 @@ if HAVE_SWIG -EXTRA_DIST = CMakeLists.txt qmf2.i SUBDIRS = examples/cpp if HAVE_RUBY_DEVEL diff --git a/cpp/bindings/qmf2/examples/cpp/Makefile.am b/cpp/bindings/qmf2/examples/cpp/Makefile.am index 062fbd0a85..8bf56ead91 100644 --- a/cpp/bindings/qmf2/examples/cpp/Makefile.am +++ b/cpp/bindings/qmf2/examples/cpp/Makefile.am @@ -21,16 +21,19 @@ INCLUDE = -I$(top_srcdir)/include AM_CPPFLAGS = $(INCLUDE) +TYPES_LIB=$(top_builddir)/src/libqpidtypes.la +MESSAGING_LIB=$(top_builddir)/src/libqpidmessaging.la + noinst_PROGRAMS=agent event_driven_list_agents list_agents print_events agent_SOURCES=agent.cpp -agent_LDADD=$(top_builddir)/src/libqmf2.la +agent_LDADD=$(top_builddir)/src/libqmf2.la $(TYPES_LIB) $(MESSAGING_LIB) list_agents_SOURCES=list_agents.cpp -list_agents_LDADD=$(top_builddir)/src/libqmf2.la +list_agents_LDADD=$(top_builddir)/src/libqmf2.la $(MESSAGING_LIB) event_driven_list_agents_SOURCES=event_driven_list_agents.cpp -event_driven_list_agents_LDADD=$(top_builddir)/src/libqmf2.la +event_driven_list_agents_LDADD=$(top_builddir)/src/libqmf2.la $(MESSAGING_LIB) print_events_SOURCES=print_events.cpp -print_events_LDADD=$(top_builddir)/src/libqmf2.la +print_events_LDADD=$(top_builddir)/src/libqmf2.la $(TYPES_LIB) $(MESSAGING_LIB) diff --git a/cpp/bindings/qmf2/python/CMakeLists.txt b/cpp/bindings/qmf2/python/CMakeLists.txt index 2e71ca34e7..1c8447116e 100644 --- a/cpp/bindings/qmf2/python/CMakeLists.txt +++ b/cpp/bindings/qmf2/python/CMakeLists.txt @@ -21,7 +21,7 @@ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") swig_add_module(cqmf2_python python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) swig_link_libraries(cqmf2_python qmf2 ${PYTHON_LIBRARIES}) @@ -31,28 +31,23 @@ set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_F ##------------------------------------ ## Install the complete Python binding ##------------------------------------ -execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cqmf2.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cqmf2.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/qmf2.py DESTINATION ${CMAKE_CURRENT_BINARY_DIR}) -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile qmf2.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") -install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile qmf2.py - WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cqmf2.py - ${CMAKE_CURRENT_BINARY_DIR}/cqmf2.pyc - ${CMAKE_CURRENT_BINARY_DIR}/cqmf2.pyo - ${CMAKE_CURRENT_BINARY_DIR}/qmf2.py - ${CMAKE_CURRENT_BINARY_DIR}/qmf2.pyc - ${CMAKE_CURRENT_BINARY_DIR}/qmf2.pyo - DESTINATION ${PYTHON_SITE_PACKAGES} + ${CMAKE_CURRENT_SOURCE_DIR}/qmf2.py + DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/_cqmf2_python.so RENAME _cqmf2.so - DESTINATION ${PYTHON_SITE_PACKAGES} + DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) +# Python compile the installed modules +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cqmf2.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cqmf2.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile qmf2.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") +install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile qmf2.py + WORKING_DIRECTORY ${PYTHON_SITEARCH_PACKAGES})") diff --git a/cpp/bindings/qmf2/python/Makefile.am b/cpp/bindings/qmf2/python/Makefile.am index 591c1408c0..309e8f8dad 100644 --- a/cpp/bindings/qmf2/python/Makefile.am +++ b/cpp/bindings/qmf2/python/Makefile.am @@ -19,7 +19,7 @@ if HAVE_PYTHON_DEVEL -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src $(QMF_INCLUDES) +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/bindings -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src $(QMF_INCLUDES) generated_file_list = \ cqmf2.cpp \ @@ -29,7 +29,7 @@ EXTRA_DIST = CMakeLists.txt python.i BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 -$(generated_file_list): $(srcdir)/python.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_python_typemaps.i +$(generated_file_list): $(srcdir)/python.i $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/python.i pylibdir = $(pyexecdir) diff --git a/cpp/bindings/qmf2/python/python.i b/cpp/bindings/qmf2/python/python.i index 02dd1632b0..6b5326f8cf 100644 --- a/cpp/bindings/qmf2/python/python.i +++ b/cpp/bindings/qmf2/python/python.i @@ -19,7 +19,7 @@ %module cqmf2 %include "std_string.i" -%include "../../swig_python_typemaps.i" +%include "qpid/swig_python_typemaps.i" /* Define the general-purpose exception handling */ %exception { @@ -37,5 +37,5 @@ } } -%include "../qmf2.i" +%include "qmf/qmf2.i" diff --git a/cpp/bindings/qmf2/qmf2.i b/cpp/bindings/qmf2/qmf2.i deleted file mode 100644 index 0f573fe3e6..0000000000 --- a/cpp/bindings/qmf2/qmf2.i +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%{ - -#include <qmf/exceptions.h> -#include <qmf/AgentEvent.h> -#include <qmf/Agent.h> -#include <qmf/AgentSession.h> -#include <qmf/ConsoleEvent.h> -#include <qmf/ConsoleSession.h> -#include <qmf/DataAddr.h> -#include <qmf/Data.h> -#include <qmf/Query.h> -#include <qmf/Schema.h> -#include <qmf/SchemaId.h> -#include <qmf/SchemaMethod.h> -#include <qmf/SchemaProperty.h> -#include <qmf/SchemaTypes.h> -#include <qmf/Subscription.h> - -%} - -%include <qpid/ImportExport.h> -%include <qpid/messaging/ImportExport.h> -%include <qpid/messaging/Duration.h> - -%include <qmf/ImportExport.h> -%include <qmf/exceptions.h> -%include <qmf/AgentEvent.h> -%include <qmf/Agent.h> -%include <qmf/AgentSession.h> -%include <qmf/ConsoleEvent.h> -%include <qmf/ConsoleSession.h> -%include <qmf/DataAddr.h> -%include <qmf/Data.h> -%include <qmf/Query.h> -%include <qmf/Schema.h> -%include <qmf/SchemaId.h> -%include <qmf/SchemaMethod.h> -%include <qmf/SchemaProperty.h> -%include <qmf/SchemaTypes.h> -%include <qmf/Subscription.h> - -%{ - -using namespace qmf; - -%}; - diff --git a/cpp/bindings/qmf2/ruby/CMakeLists.txt b/cpp/bindings/qmf2/ruby/CMakeLists.txt index 1cb969f7dc..70b3e917f9 100644 --- a/cpp/bindings/qmf2/ruby/CMakeLists.txt +++ b/cpp/bindings/qmf2/ruby/CMakeLists.txt @@ -22,7 +22,9 @@ ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) -include_directories(${RUBY_INCLUDE_DIRS} ${qpid-cpp_SOURCE_DIR}/include) +include_directories(${RUBY_INCLUDE_DIRS} + ${qpid-cpp_SOURCE_DIR}/include + ${qpid-cpp_SOURCE_DIR}/bindings) swig_add_module(cqmf2_ruby ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) swig_link_libraries(cqmf2_ruby qmf2 ${RUBY_LIBRARY}) @@ -32,7 +34,7 @@ swig_link_libraries(cqmf2_ruby qmf2 ${RUBY_LIBRARY}) ##---------------------------------- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqmf2_ruby.so RENAME cqmf2.so - DESTINATION ${RUBY_ARCH_DIR} + DESTINATION ${RUBY_PFX_ARCH_DIR} COMPONENT ${QPID_COMPONENT_CLIENT} ) diff --git a/cpp/bindings/qmf2/ruby/Makefile.am b/cpp/bindings/qmf2/ruby/Makefile.am index a03bd6d5e6..9952edb972 100644 --- a/cpp/bindings/qmf2/ruby/Makefile.am +++ b/cpp/bindings/qmf2/ruby/Makefile.am @@ -19,7 +19,7 @@ if HAVE_RUBY_DEVEL -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src $(QMF_INCLUDES) +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/bindings -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src $(QMF_INCLUDES) EXTRA_DIST = CMakeLists.txt ruby.i BUILT_SOURCES = cqmf2.cpp @@ -27,7 +27,7 @@ SWIG_FLAGS = -w362,401 rubylibdir = $(RUBY_LIB) -cqmf2.cpp: $(srcdir)/ruby.i $(srcdir)/../qmf2.i $(srcdir)/../../swig_ruby_typemaps.i +cqmf2.cpp: $(srcdir)/ruby.i $(SWIG) -ruby -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqmf2.cpp $(srcdir)/ruby.i rubylibarchdir = $(RUBY_LIB_ARCH) diff --git a/cpp/bindings/qmf2/ruby/ruby.i b/cpp/bindings/qmf2/ruby/ruby.i index 1070c65a44..0254017555 100644 --- a/cpp/bindings/qmf2/ruby/ruby.i +++ b/cpp/bindings/qmf2/ruby/ruby.i @@ -18,8 +18,10 @@ */ %module cqmf2 +/* Ruby doesn't have a != operator*/ +#pragma SWIG nowarn=378 %include "std_string.i" -%include "../../swig_ruby_typemaps.i" +%include "qpid/swig_ruby_typemaps.i" /* Define the general-purpose exception handling */ %exception { @@ -32,4 +34,4 @@ } } -%include "../qmf2.i" +%include "qmf/qmf2.i" diff --git a/cpp/bindings/qpid/CMakeLists.txt b/cpp/bindings/qpid/CMakeLists.txt deleted file mode 100644 index 7c9f76f991..0000000000 --- a/cpp/bindings/qpid/CMakeLists.txt +++ /dev/null @@ -1,41 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - - -include(FindSWIG) -include(UseSWIG) -include(FindRuby) -include(FindPythonLibs) -include(FindPerlLibs) - -if (SWIG_FOUND) - set(CMAKE_SWIG_FLAGS "-w361,362,401,467,503") - - if (PYTHONLIBS_FOUND) - add_subdirectory(python) - endif (PYTHONLIBS_FOUND) - - if (RUBY_FOUND) - add_subdirectory(ruby) - endif (RUBY_FOUND) - - if (PERLLIBS_FOUND) - add_subdirectory(perl) - endif (PERLLIBS_FOUND) -endif (SWIG_FOUND) diff --git a/cpp/bindings/qpid/Makefile.am b/cpp/bindings/qpid/Makefile.am index ae81696f27..aace6f2d95 100644 --- a/cpp/bindings/qpid/Makefile.am +++ b/cpp/bindings/qpid/Makefile.am @@ -21,8 +21,6 @@ SUBDIRS = dotnet if HAVE_SWIG -EXTRA_DIST = CMakeLists.txt qpid.i - if HAVE_RUBY_DEVEL SUBDIRS += ruby endif @@ -33,18 +31,18 @@ endif if HAVE_PERL_DEVEL -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -I$(PERL_INC) +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/bindings -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src -I$(PERL_INC) -EXTRA_DIST += perl/perl.i perl/CMakeLists.txt +EXTRA_DIST = perl/perl.i perl/CMakeLists.txt BUILT_SOURCES = perl/cqpid_perl.cpp SWIG_FLAGS = -w362,401 -perl/cqpid_perl.cpp: $(srcdir)/perl/perl.i $(srcdir)/qpid.i $(srcdir)/../swig_perl_typemaps.i +perl/cqpid_perl.cpp: $(srcdir)/perl/perl.i $(SWIG) -perl -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o perl/cqpid_perl.cpp $(srcdir)/perl/perl.i perl/Makefile: perl/cqpid_perl.cpp cd perl; \ - $(PERL) Makefile.PL PREFIX=$(prefix) LIB=$(PERL_ARCHLIB) ; \ + $(PERL) Makefile.PL PREFIX=$(prefix) ; \ cd .. all-local: perl/Makefile @@ -54,7 +52,7 @@ all-local: perl/Makefile install-exec-local: cd perl ; \ - $(MAKE) pure_install DESTDIR=$(prefix) ; \ + $(MAKE) pure_install ; \ cd .. clean-local: @@ -72,7 +70,6 @@ maintainer-clean-local: $(PERL) maintainer-clean ; \ cd .. -DISTCLEANFILES = perl/Makefile.PL CLEANFILES = perl/cqpid_perl.cpp perl/Makefile.old perl/cqpid_perl.pm endif diff --git a/cpp/bindings/qpid/dotnet/configure-windows.ps1 b/cpp/bindings/qpid/dotnet/configure-windows.ps1 index 162ac272b4..60b2b539bd 100644 --- a/cpp/bindings/qpid/dotnet/configure-windows.ps1 +++ b/cpp/bindings/qpid/dotnet/configure-windows.ps1 @@ -24,8 +24,8 @@ # This script configures a qpid\cpp developer build environment under Windows
# to enable working with cpp\bindings\qpid\dotnet binding source code.
#
-# * Supports multiple versions of Visual Studio (VS2008, VS2010) as CMake
-# generator.
+# * Supports multiple versions of Visual Studio (VS2008, VS2010, VS2012)
+# as CMake generator.
#
# * Supports 32-bit and/or 64-bit development platforms.
#
@@ -148,10 +148,11 @@ $global:txtWH = 'Write-Host' #############################
# Visual Studio version selection dialog items and choice
#
-[array]$global:VsVersionCmakeChoiceList = "Visual Studio 2010", "Visual Studio 2008"
+[array]$global:VsVersionCmakeChoiceList = "Visual Studio 2012", "Visual Studio 2010", "Visual Studio 2008"
$global:vsVersion = ''
$global:cmakeGenerator = ''
$global:vsSubdir = ''
+$global:cmakeCompiler = ''
#############################
# Select-Folder
@@ -352,18 +353,26 @@ ECHO Environment set for $slnName $studioVersion $vsPlatform $nBits-bit developm function Return-DropDown {
if ($DropDown.SelectedItem -ne $null) {
$global:vsVersion = $DropDown.SelectedItem.ToString()
- if ($global:vsVersion -eq 'Visual Studio 2010') {
- $global:cmakeGenerator = "Visual Studio 10"
- $global:vsSubdir = "msvc10"
+ if ($global:vsVersion -eq 'Visual Studio 2012') {
+ $global:cmakeGenerator = "Visual Studio 11"
+ $global:vsSubdir = "msvc11"
+ $global:cmakeCompiler = "-vc110"
} else {
- if ($global:vsVersion -eq 'Visual Studio 2008') {
- $global:cmakeGenerator = "Visual Studio 9 2008"
- $global:vsSubdir = "msvc9"
- } else {
- Write-Host "Visual Studio must be 2008 or 2010"
- exit
- }
- }
+ if ($global:vsVersion -eq 'Visual Studio 2010') {
+ $global:cmakeGenerator = "Visual Studio 10"
+ $global:vsSubdir = "msvc10"
+ $global:cmakeCompiler = "-vc100"
+ } else {
+ if ($global:vsVersion -eq 'Visual Studio 2008') {
+ $global:cmakeGenerator = "Visual Studio 9 2008"
+ $global:vsSubdir = "msvc9"
+ $global:cmakeCompiler = "-vc90"
+ } else {
+ Write-Host "Visual Studio must be 2008, 2010, or 2012"
+ exit
+ }
+ }
+ }
$Form.Close()
Write-Host "Selected generator: $global:cmakeGenerator"
}
@@ -496,7 +505,7 @@ if ($make32) { $env:BOOST_ROOT = "$boost32"
cd "$build32"
Write-Host "Running 32-bit CMake in $build32 ..."
- CMake -G "$global:cmakeGenerator" "-DCMAKE_INSTALL_PREFIX=install_x86" $cppDir
+ CMake -G "$global:cmakeGenerator" "-DGEN_DOXYGEN=No" "-DCMAKE_INSTALL_PREFIX=install_x86" "-DBoost_COMPILER=$global:cmakeCompiler" $cppDir
} else {
Write-Host "Skipped 32-bit CMake."
}
@@ -508,7 +517,7 @@ if ($make64) { $env:BOOST_ROOT = "$boost64"
cd "$build64"
Write-Host "Running 64-bit CMake in $build64"
- CMake -G "$global:cmakeGenerator Win64" "-DCMAKE_INSTALL_PREFIX=install_x64" $cppDir
+ CMake -G "$global:cmakeGenerator Win64" "-DGEN_DOXYGEN=No" "-DCMAKE_INSTALL_PREFIX=install_x64" "-DBoost_COMPILER=$global:cmakeCompiler" $cppDir
} else {
Write-Host "Skipped 64-bit CMake."
}
diff --git a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/csharp.map.callback.receiver.cs b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/csharp.map.callback.receiver.cs index b1ba949e07..3bc22b2ce8 100644 --- a/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/csharp.map.callback.receiver.cs +++ b/cpp/bindings/qpid/dotnet/examples/csharp.map.callback.receiver/csharp.map.callback.receiver.cs @@ -153,6 +153,21 @@ namespace Org.Apache.Qpid.Messaging.Examples /// <summary>
+ /// SessionReceiver implements the ISessionReceiver interface.
+ /// It is the exception function that receives all exception messages
+ /// It may be called any time server is running.
+ /// It is always called on server's private thread.
+ /// After this is called then the sessionReceiver and private thread are closed.
+ /// </summary>
+ /// <param name="exception">The exception.</param>
+ public void SessionException(Exception exception)
+ {
+ // A typical application will take more action here.
+ Console.WriteLine("{0} Exception caught.", exception.ToString());
+ }
+
+
+ /// <summary>
/// Usage
/// </summary>
/// <param name="url">Connection target</param>
@@ -259,8 +274,17 @@ namespace Org.Apache.Qpid.Messaging.Examples //
// Close the receiver and the connection.
//
- receiver.Close();
- connection.Close();
+ try
+ {
+ receiver.Close();
+ connection.Close();
+ }
+ catch (Exception exception)
+ {
+ // receiver or connection may throw if they closed in error.
+ // A typical application will take more action here.
+ Console.WriteLine("{0} Closing exception caught.", exception.ToString());
+ }
return 0;
}
}
diff --git a/cpp/bindings/qpid/dotnet/msvc9/org.apache.qpid.messaging.sessionreceiver.sln b/cpp/bindings/qpid/dotnet/msvc9/org.apache.qpid.messaging.sessionreceiver.sln index 9ed7d4df3a..112511e5e5 100644 --- a/cpp/bindings/qpid/dotnet/msvc9/org.apache.qpid.messaging.sessionreceiver.sln +++ b/cpp/bindings/qpid/dotnet/msvc9/org.apache.qpid.messaging.sessionreceiver.sln @@ -21,7 +21,7 @@ Microsoft Visual Studio Solution File, Format Version 10.00 Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Org.Apache.Qpid.Messaging", "..\src\msvc9\org.apache.qpid.messaging.vcproj", "{AA5A3B83-5F98-406D-A01C-5A921467A57D}"
EndProject
-Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "org.apache.qpid.messaging.sessionreceiver", "..\src\msvc9\sessionreceiver\org.apache.qpid.messaging.sessionreceiver.csproj", "{B0A51CEC-30A2-4C2E-90BE-AE95107EAA05}"
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "org.apache.qpid.messaging.sessionreceiver", "..\src\sessionreceiver\msvc9\org.apache.qpid.messaging.sessionreceiver.csproj", "{B0A51CEC-30A2-4C2E-90BE-AE95107EAA05}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
diff --git a/cpp/bindings/qpid/dotnet/src/Receiver.cpp b/cpp/bindings/qpid/dotnet/src/Receiver.cpp index bbd7dd4c52..43bb7dd3cb 100644 --- a/cpp/bindings/qpid/dotnet/src/Receiver.cpp +++ b/cpp/bindings/qpid/dotnet/src/Receiver.cpp @@ -344,9 +344,34 @@ namespace Messaging { void Receiver::Close()
{
- msclr::lock lk(privateLock);
- ThrowIfDisposed();
+ System::Exception ^ newException = nullptr;
+ Message ^ newMessage = nullptr;
- nativeObjPtr->close();
+ try
+ {
+ msclr::lock lk(privateLock);
+ ThrowIfDisposed();
+
+ nativeObjPtr->close();
+ }
+ catch (const ::qpid::types::Exception & error)
+ {
+ String ^ errmsg = gcnew String(error.what());
+ newException = gcnew QpidException(errmsg);
+ }
+ finally
+ {
+ if (newException != nullptr)
+ {
+ if (newMessage != nullptr)
+ {
+ delete newMessage;
+ }
+ }
+ }
+ if (newException != nullptr)
+ {
+ throw newException;
+ }
}
}}}}
diff --git a/cpp/bindings/qpid/dotnet/src/sessionreceiver/sessionreceiver.cs b/cpp/bindings/qpid/dotnet/src/sessionreceiver/sessionreceiver.cs index 680732068f..a15a8d60fe 100644 --- a/cpp/bindings/qpid/dotnet/src/sessionreceiver/sessionreceiver.cs +++ b/cpp/bindings/qpid/dotnet/src/sessionreceiver/sessionreceiver.cs @@ -37,6 +37,7 @@ namespace Org.Apache.Qpid.Messaging.SessionReceiver public interface ISessionReceiver
{
void SessionReceiver(Receiver receiver, Message message);
+ void SessionException(Exception exception);
}
@@ -67,25 +68,32 @@ namespace Org.Apache.Qpid.Messaging.SessionReceiver {
Receiver rcvr;
Message msg;
-
- keepRunning = true;
- while (keepRunning)
+ try
{
- rcvr = session.NextReceiver(DurationConstants.SECOND);
-
- if (null != rcvr)
+ keepRunning = true;
+ while (keepRunning)
{
- if (keepRunning)
+ rcvr = session.NextReceiver(DurationConstants.SECOND);
+
+ if (null != rcvr)
{
- msg = rcvr.Fetch(DurationConstants.SECOND);
- this.callback.SessionReceiver(rcvr, msg);
+ if (keepRunning)
+ {
+ msg = rcvr.Fetch(DurationConstants.SECOND);
+ this.callback.SessionReceiver(rcvr, msg);
+ }
}
+ //else
+ // receive timed out
+ // EventEngine exits the nextReceiver() function periodically
+ // in order to test the keepRunning flag
}
- //else
- // receive timed out
- // EventEngine exits the nextReceiver() function periodically
- // in order to test the keepRunning flag
}
+ catch (Exception e)
+ {
+ this.callback.SessionException(e);
+ }
+
// Private thread is now exiting.
}
diff --git a/cpp/bindings/qpid/examples/perl/README b/cpp/bindings/qpid/examples/perl/README deleted file mode 100644 index 1e113f1fa0..0000000000 --- a/cpp/bindings/qpid/examples/perl/README +++ /dev/null @@ -1,26 +0,0 @@ -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. - - -The examples in this directory are written against the raw Perl -binding ("cqpid"). This binding is identical to the C++ messaging (in -namespace qpid::messaging). - -It is desired that a layer will be written over this interface (called -"qpid") that provides a more Perl-specific API. When this occurs, -these examples will be changed to use the new Perl API. - diff --git a/cpp/bindings/qpid/examples/perl/client.pl b/cpp/bindings/qpid/examples/perl/client.pl index 19d9d3f14f..586beb787e 100644..100755 --- a/cpp/bindings/qpid/examples/perl/client.pl +++ b/cpp/bindings/qpid/examples/perl/client.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -20,47 +20,59 @@ use strict; use warnings; -use cqpid_perl; +use qpid; -my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; -my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; +my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; +my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; - -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +# creates a new connection instance +my $connection = new qpid::messaging::Connection( $url, $connectionOptions ); eval { -$connection->open(); -my $session = $connection->createSession(); + # open the connection and create a session for interacting with it + $connection->open(); -my $sender = $session->createSender("service_queue"); + my $session = $connection->create_session(); + my $sender = $session->create_sender("service_queue"); -#create temp queue & receiver... -my $responseQueue = new cqpid_perl::Address("#response-queue; {create:always, delete:always}"); -my $receiver = $session->createReceiver($responseQueue); + # create an address and receiver for incoming messages + # the queue will be created always, and will be deleted + # when the receive disconnects + my $responseQueue = new qpid::messaging::Address( + "#response-queue; {create:always, delete:always}"); + my $receiver = $session->create_receiver($responseQueue); -#Now send some messages... + # Now send some messages... -my @s = ( - "Twas brillig, and the slithy toves", - "Did gire and gymble in the wabe.", - "All mimsy were the borogroves,", - "And the mome raths outgrabe." - ); + my @s = ( + "Twas brillig, and the slithy toves", + "Did gire and gymble in the wabe.", + "All mimsy were the borogroves,", + "And the mome raths outgrabe." + ); -my $request = new cqpid_perl::Message(); -$request->setReplyTo($responseQueue); -for (my $i=0; $i<4; $i++) { - $request->setContent($s[$i]); - $sender->send($request); - my $response = $receiver->fetch(); - print $request->getContent() . " -> " . $response->getContent() . "\n"; -} + # create the message object, and set a reply-to address + # so that the server knows where to send responses + # the message object will be reused to send each line + my $request = new qpid::messaging::Message(); + $request->set_reply_to($responseQueue); + for ( my $i = 0 ; $i < 4 ; $i++ ) { + $request->set_content( $s[$i] ); + $sender->send($request); + + # wait for the response to the last line sent + # the message will be taken directly from the + # broker's queue rather than waiting for it + # to be queued locally + my $response = $receiver->fetch(); + print $request->get_content() . " -> " + . $response->get_content() . "\n"; + } -$connection->close(); + # close the connection + $connection->close(); }; if ($@) { die $@; } - - diff --git a/cpp/bindings/qpid/examples/perl/drain.pl b/cpp/bindings/qpid/examples/perl/drain.pl index 60ac0c50ed..f7a710c485 100644..100755 --- a/cpp/bindings/qpid/examples/perl/drain.pl +++ b/cpp/bindings/qpid/examples/perl/drain.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -20,79 +20,135 @@ use strict; use warnings; -use cqpid_perl; +use qpid; use Getopt::Long; +use Pod::Usage; -my $url = "127.0.0.1"; -my $timeout = 60; -my $forever = 0; -my $count = 1; +my $url = "127.0.0.1"; +my $timeout = 0; +my $forever = 0; +my $count = 0; my $connectionOptions = ""; -my $address = "amq.direct"; +my $address = "amq.direct"; +my $help; my $result = GetOptions( - "broker|b=s" => \ $url, - "timeout|t=i" => \ $timeout, - "forever|f" => \ $forever, - "connection-options=s" => \ $connectionOptions, - "count|c=i" => \ $count, -); - -if (! $result) { - print "Usage: perl drain.pl [OPTIONS]\n"; -} + "broker|b=s" => \$url, + "timeout|t=i" => \$timeout, + "forever|f" => \$forever, + "connection-options=s" => \$connectionOptions, + "count|c=i" => \$count, + "help|h" => \$help +) || pod2usage( -verbose => 0 ); + +pod2usage( -verbose => 1 ) if $help; -if ($#ARGV ge 0) { - $address = $ARGV[0] +if ( $#ARGV ge 0 ) { + $address = $ARGV[0]; } sub getTimeout { - return ($forever) ? $cqpid_perl::Duration::FOREVER : new cqpid_perl::Duration($timeout*1000); + + # returns either the named duration FOREVER if the + # forever cmdline argument was used, otherwise creates + # a new Duration of the specified length + return ($forever) + ? qpid::messaging::Duration::FOREVER + : new qpid::messaging::Duration( $timeout * 1000 ); } +sub printProperties { + my $h = shift(); + return qq[{${\(join', ',map"'$_': '$h->{$_}'",keys%$h)}}]; +} -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +# create a connection object +my $connection = new qpid::messaging::Connection( $url, $connectionOptions ); eval { + # open the connection, then create a session and receiver $connection->open(); - my $session = $connection->createSession(); - my $receiver = $session->createReceiver($address); + my $session = $connection->create_session(); + my $receiver = $session->create_receiver($address); my $timeout = getTimeout(); + my $message = new qpid::messaging::Message(); + my $i = 0; + + for ( ; ; ) { + eval { $message = $receiver->fetch($timeout); }; - my $message = new cqpid_perl::Message(); - my $i = 0; + if ($@) { + last; + } + + # check if the message was on that was redelivered + my $redelivered = + ( $message->get_redelivered ) ? "redelivered=True, " : ""; + print "Message(" + . $redelivered + . "properties=" + . printProperties( $message->get_properties() ) + . ", content='"; - while($receiver->fetch($message, $timeout)) { - print "Message(properties=" . $message->getProperties() . ",content='"; - if ($message->getContentType() eq "amqp/map") { - my $content = cqpid_perl::decodeMap($message); - map{ print "\n$_ => $content->{$_}"; } keys %{$content}; + # if the message content was a map, then we will print + # it out as a series of name => value pairs + if ( $message->get_content_type() eq "amqp/map" ) { + my $content = $message->get_content(); + map { print "\n$_ => $content->{$_}"; } keys %{$content}; } else { - print $message->getContent(); + # it's not a map, so just print the content as a string + print $message->get_content(); } print "')\n"; - - my $replyto = $message->getReplyTo(); - if ($replyto->getName()) { - print "Replying to " . $message->getReplyTo()->str() . "...\n"; - my $sender = $session->createSender($replyto); - my $response = new cqpid_perl::Message("received by the server."); + + # if the message had a reply-to address, then we'll send a + # response back letting the send know the message was processed + my $replyto = $message->get_reply_to(); + if ( $replyto->get_name() ) { + print "Replying to " . $message->get_reply_to()->str() . "...\n"; + + # create a temporary sender for the specified queue + my $sender = $session->create_sender($replyto); + my $response = + new qpid::messaging::Message("received by the server."); $sender->send($response); } + + # acknowledge all messages received on this queue so far $session->acknowledge(); - if ($count and (++$i ==$count)) { + if ( $count and ( ++$i == $count ) ) { last; } } + + # close everything to clean up $receiver->close(); $session->close(); $connection->close(); }; if ($@) { - $connection->close(); - die $@; + $connection->close(); + die $@; } +__END__ + +=head1 NAME + +drain - Drains messages from the specified address + +=head1 SYNOPSIS + + Options: + -h, --help show this message + -b VALUE, --broker VALUE url of broker to connect to + -t VALUE, --timeout VALUE timeout in seconds to wait before exiting + -f, --forever ignore timeout and wait forever + --connection-options VALUE connection options string in the form {name1:value1, name2:value2} + -c VALUE, --count VALUE number of messages to read before exiting + +=cut + diff --git a/cpp/bindings/qpid/examples/perl/hello_world.pl b/cpp/bindings/qpid/examples/perl/hello_world.pl index a96b98a002..6ec7d52f1f 100644..100755 --- a/cpp/bindings/qpid/examples/perl/hello_world.pl +++ b/cpp/bindings/qpid/examples/perl/hello_world.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -21,35 +21,35 @@ use strict; use warnings; use Data::Dumper; -use cqpid_perl; +use qpid; my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672"; my $address = ( @ARGV > 1 ) ? $ARGV[0] : "amq.topic"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : ""; -my $connection = new cqpid_perl::Connection($broker, $connectionOptions); +# create a connection +my $connection = new qpid::messaging::Connection( $broker, $connectionOptions ); eval { + # open the connection and create a session, and both a sender a receive $connection->open(); - my $session = $connection->createSession(); - my $receiver = $session->createReceiver($address); - my $sender = $session->createSender($address); + my $session = $connection->create_session(); - $sender->send(new cqpid_perl::Message("Hello world!")); + my $receiver = $session->create_receiver($address); + my $sender = $session->create_sender($address); - #my $duration = new cqpid_perl::Duration(1000); - #print ">>>" . $duration->getMilliseconds() . "\n"; + # send a simple message + $sender->send( new qpid::messaging::Message("Hello world!") ); - my $message = $receiver->fetch($cqpid_perl::Duration::SECOND); + # receive the message, fetching it directly from the broker + my $message = $receiver->fetch(qpid::messaging::Duration::SECOND); - #$message->setDurable(1); - #print "Durable: " . $message->getDurable() . "\n"; - #print Dumper($message->getProperties()); - - print $message->getContent() . "\n"; + # output the message content, then acknowledge it + print $message->get_content() . "\n"; $session->acknowledge(); + # close the connection $connection->close(); }; diff --git a/cpp/bindings/qpid/examples/perl/hello_xml.pl b/cpp/bindings/qpid/examples/perl/hello_xml.pl index cebf2ceee6..8d77c4b2b8 100644..100755 --- a/cpp/bindings/qpid/examples/perl/hello_xml.pl +++ b/cpp/bindings/qpid/examples/perl/hello_xml.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -20,7 +20,7 @@ use strict; use warnings; -use cqpid_perl; +use qpid; my $broker = ( @ARGV > 0 ) ? $ARGV[0] : "localhost:5672"; my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; @@ -36,23 +36,25 @@ END my $address = <<END; xml-exchange; { -create: always, +create: always, node: { type: topic, x-declare: { type: xml } }, link: { x-bindings: [{ exchange: xml-exchange, key: weather, arguments: { xquery:" $query" } }] }} END - -my $connection = new cqpid_perl::Connection($broker, $connectionOptions); +# create a connection object +my $connection = new qpid::messaging::Connection( $broker, $connectionOptions ); eval { + # open the connection, then create from it a session + # from the session, create a receiver to handle incoming messages $connection->open(); - my $session = $connection->createSession(); + my $session = $connection->create_session(); + my $receiver = $session->create_receiver($address); - my $receiver = $session->createReceiver($address); - - my $message = new cqpid_perl::Message(); + # create a message and set its contentn + my $message = new qpid::messaging::Message(); my $content = <<END; <weather> @@ -62,14 +64,19 @@ eval { <dewpoint>35</dewpoint> </weather> END - - $message->setContent($content); - my $sender = $session->createSender('xml-exchange/weather'); + + $message->set_content($content); + + # create a sender for the xml-exchange/weater topic + # then send the message + my $sender = $session->create_sender('xml-exchange/weather'); $sender->send($message); - + + # wait for the response and then output it to the screen my $response = $receiver->fetch(); - print $response->getContent() . "\n"; + print $response->get_content() . "\n"; + # close the connection $connection->close(); }; diff --git a/cpp/bindings/qpid/examples/perl/map_receiver.pl b/cpp/bindings/qpid/examples/perl/map_receiver.pl index 2e2611e38f..a538adf380 100644..100755 --- a/cpp/bindings/qpid/examples/perl/map_receiver.pl +++ b/cpp/bindings/qpid/examples/perl/map_receiver.pl @@ -1,4 +1,4 @@ -#! /usr/bin/perl5 +#! /usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -21,25 +21,33 @@ use strict; use warnings; use Data::Dumper; -use cqpid_perl; +use qpid; -my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; -my $address = ( @ARGV > 1 ) ? $ARGV[0] : "message_queue; {create: always}"; +my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; +my $address = ( @ARGV > 1 ) ? $ARGV[0] : "message_queue; {create: always}"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[1] : ""; -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +# create a connection object +my $connection = new qpid::messaging::Connection( $url, $connectionOptions ); eval { + # open the connection, then create a session from it $connection->open(); - my $session = $connection->createSession(); - my $receiver = $session->createReceiver($address); + my $session = $connection->create_session(); - my $content = cqpid_perl::decodeMap($receiver->fetch()); - #my $content = cqpid_perl::decodeList($receiver->fetch()); - + # create a receiver for the session, subscribed the the specified queue + my $receiver = $session->create_receiver($address); + # wait for a message to appear in the queue + my $message = $receiver->fetch(); + + # display the content of the message + my $content = $message->get_content(); print Dumper($content); + # acknowledge the message, removing it from the queue $session->acknowledge(); + + # close everything, cleaning up $receiver->close(); $connection->close(); }; diff --git a/cpp/bindings/qpid/examples/perl/map_sender.pl b/cpp/bindings/qpid/examples/perl/map_sender.pl index 4107cd48b9..27063ef780 100644..100755 --- a/cpp/bindings/qpid/examples/perl/map_sender.pl +++ b/cpp/bindings/qpid/examples/perl/map_sender.pl @@ -1,4 +1,4 @@ -#! /usr/bin/perl5 +#! /usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -21,29 +21,39 @@ use strict; use warnings; use Data::Dumper; -use cqpid_perl; +use qpid; -my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; -my $address = ( @ARGV > 1 ) ? $ARGV[1] : "message_queue; {create: always}"; +my $url = ( @ARGV > 0 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; +my $address = ( @ARGV > 1 ) ? $ARGV[1] : "message_queue; {create: always}"; my $connectionOptions = ( @ARGV > 2 ) ? $ARGV[2] : ""; -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +# create a new connection object +my $connection = new qpid::messaging::Connection( $url, $connectionOptions ); eval { - $connection->open(); - - my $session = $connection->createSession(); - my $sender = $session->createSender($address); - - my $message = new cqpid_perl::Message(); - my $content = { id => 987654321, - name => "Widget", - percent => sprintf("%.2f", 0.99), - colours => [ qw (red green white) ], - }; - cqpid_perl::encode($content, $message); - $sender->send($message, 1); + # open the connection and create a session + $connection->open(); + my $session = $connection->create_session(); + + # create a sender and connect it to the supplied address string + my $sender = $session->create_sender($address); + + # create a message and set the content to be a map of values + my $message = new qpid::messaging::Message(); + my $content = { + id => 987654321, + name => "Widget", + percent => sprintf( "%.2f", 0.99 ), + colours => [qw (red green white)], + }; + $message->set_content($content); + + # send the message + $sender->send( $message, 1 ); + + # close the connection and session + $session->close(); $connection->close(); }; diff --git a/cpp/bindings/qpid/examples/perl/server.pl b/cpp/bindings/qpid/examples/perl/server.pl index b14da565b9..be43655aeb 100644..100755 --- a/cpp/bindings/qpid/examples/perl/server.pl +++ b/cpp/bindings/qpid/examples/perl/server.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -20,43 +20,64 @@ use strict; use warnings; -use cqpid_perl; +use qpid; -my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; -my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; +my $url = ( @ARGV == 1 ) ? $ARGV[0] : "amqp:tcp:127.0.0.1:5672"; +my $connectionOptions = ( @ARGV > 1 ) ? $ARGV[1] : ""; - -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +# create a connection object +my $connection = new qpid::messaging::Connection( $url, $connectionOptions ); eval { + + # connect to the broker and create a session $connection->open(); - my $session = $connection->createSession(); + my $session = $connection->create_session(); - my $receiver = $session->createReceiver("service_queue; {create: always}"); + # create a receiver for accepting incoming messages + my $receiver = $session->create_receiver("service_queue; {create: always}"); + # go into an infinite loop to receive messages and process them while (1) { + + # wait for the next message to be processed my $request = $receiver->fetch(); - my $address = $request->getReplyTo(); + + + # get the address for sending replies + # if no address was supplised then we can't really respond, so + # only process when one is present + my $address = $request->get_reply_to(); if ($address) { - my $sender = $session->createSender($address); - my $s = $request->getContent(); + + # a temporary sender for sending to the response queue + my $sender = $session->create_sender($address); + my $s = $request->get_content(); $s = uc($s); - my $response = new cqpid_perl::Message($s); + + # create the response message and send it + my $response = new qpid::messaging::Message($s); $sender->send($response); - print "Processed request: " . $request->getContent() . " -> " . $response->getContent() . "\n"; + print "Processed request: " + . $request->get_content() . " -> " + . $response->get_content() . "\n"; + + # acknowledge the message since it was processed $session->acknowledge(); } else { - print "Error: no reply address specified for request: " . $request->getContent() . "\n"; + print "Error: no reply address specified for request: " + . $request->get_content() . "\n"; $session->reject($request); } } -$connection->close(); + # close connections to clean up + $session->close(); + $connection->close(); }; if ($@) { die $@; } - diff --git a/cpp/bindings/qpid/examples/perl/spout.pl b/cpp/bindings/qpid/examples/perl/spout.pl index 7365e732bf..d8ac860143 100644..100755 --- a/cpp/bindings/qpid/examples/perl/spout.pl +++ b/cpp/bindings/qpid/examples/perl/spout.pl @@ -1,4 +1,4 @@ -#!/usr/bin/perl +#!/usr/bin/env perl # # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file @@ -20,117 +20,145 @@ use strict; use warnings; -use cqpid_perl; +use qpid; use Getopt::Long; +use Pod::Usage; use Time::Local; -my $url = "127.0.0.1"; +my $url = "127.0.0.1"; my $timeout = 0; my $count = 1; my $id = ""; my $replyto = ""; my @properties; my @entries; -my $content = ""; +my $content = ""; my $connectionOptions = ""; -my $address = "amq.direct"; +my $address = "amq.direct"; +my $help; my $result = GetOptions( - "broker|b=s" => \ $url, - "timeout|t=i" => \ $timeout, - "count|c=i" => \ $count, - "id|i=s" => \ $id, - "replyto=s" => \ $replyto, - "property|p=s@" => \ @properties, - "map|m=s@" => \ @entries, - "content=s" => \ $content, - "connection-options=s" => \ $connectionOptions, -); - - -if (! $result) { - print "Usage: perl drain.pl [OPTIONS]\n"; + "broker|b=s" => \$url, + "timeout|t=i" => \$timeout, + "count|c=i" => \$count, + "id|i=s" => \$id, + "replyto=s" => \$replyto, + "property|p=s@" => \@properties, + "map|m=s@" => \@entries, + "content=s" => \$content, + "connection-options=s" => \$connectionOptions, + "help|h" => \$help +) || pod2usage( -verbose => 0 ); + +pod2usage( -verbose => 1 ) if $help; + +if ( $#ARGV ge 0 ) { + $address = $ARGV[0]; } - -if ($#ARGV ge 0) { - $address = $ARGV[0] -} - - sub setEntries { my ($content) = @_; foreach (@entries) { - my ($name, $value) = split("=", $_); + my ( $name, $value ) = split( "=", $_ ); $content->{$name} = $value; } } - sub setProperties { my ($message) = @_; foreach (@properties) { - my ($name, $value) = split("=", $_); - $message->getProperties()->{$name} = $value; + my ( $name, $value ) = split( "=", $_ ); + $message->setProperty( $name, $value ); } } -my $connection = new cqpid_perl::Connection($url, $connectionOptions); +# create a connection object +my $connection = new qpid::messaging::Connection( $url, $connectionOptions ); eval { + # open the connection, create a session and then a sender $connection->open(); - my $session = $connection->createSession(); - my $sender = $session->createSender($address); + my $session = $connection->create_session(); + my $sender = $session->create_sender($address); - my $message = new cqpid_perl::Message(); + # create a message to be sent + my $message = new qpid::messaging::Message(); setProperties($message) if (@properties); if (@entries) { my $content = {}; setEntries($content); - cqpid_perl::encode($content, $message); + $message->set_content($content); } elsif ($content) { - $message->setContent($content); - $message->setContentType("text/plain"); + $message->set_content($content); + $message->set_content_type("text/plain"); } + # if a reply-to address was supplied, then create a receiver from the + # session and wait for a response to be sent my $receiver; if ($replyto) { - my $responseQueue = new cqpid_perl::Address($replyto); - $receiver = $session->createReceiver($responseQueue); - $message->setReplyTo($responseQueue); + my $responseQueue = new qpid::messaging::Address($replyto); + $receiver = $session->create_receiver($responseQueue); + $message->set_reply_to($responseQueue); } my $start = localtime; - my @s = split(/[:\s]/, $start); - my $s = "$s[3]$s[4]$s[5]"; - my $n = $s; - - for (my $i = 0; - ($i < $count || $count == 0) and - ($timeout == 0 || abs($n - $s) < $timeout); - $i++) { + my @s = split( /[:\s]/, $start ); + my $s = "$s[3]$s[4]$s[5]"; + my $n = $s; + + for ( + my $i = 0 ; + ( $i < $count || $count == 0 ) + and ( $timeout == 0 || abs( $n - $s ) < $timeout ) ; + $i++ + ) + { $sender->send($message); if ($receiver) { + print "Waiting for a response.\n"; my $response = $receiver->fetch(); - print "$i -> " . $response->getContent() . "\n"; + print "$i -> " . $response->get_content() . "\n"; } my $now = localtime; - my @n = split(/[:\s]/, $now); - my $n = "$n[3]$n[4]$n[5]"; + my @n = split( /[:\s]/, $now ); + my $n = "$n[3]$n[4]$n[5]"; } $session->sync(); $connection->close(); }; if ($@) { - $connection->close(); - die $@; + $connection->close(); + die $@; } +__END__ + +=head1 NAME + +spout - Send messages to the specified address + +=head1 SYNOPSIS + + Usage: spout [OPTIONS] ADDRESS + + Options: + -h, --help show this message + -b VALUE, --broker VALUE url of broker to connect to + -t VALUE, --timeout VALUE exit after the specified time + -c VALUE, --count VALUE stop after count messageshave been sent, zero disables + -i VALUE, --id VALUE use the supplied id instead of generating one + --replyto VALUE specify reply-to value + -P VALUE, --property VALUE specify message property + -M VALUE, --map VALUE specify entry for map content + --content VALUE specify textual content + --connection-options VALUE connection options string in the form {name1:value1, name2:value2} +=cut diff --git a/cpp/bindings/qpid/perl/CMakeLists.txt b/cpp/bindings/qpid/perl/CMakeLists.txt index 0d66c144db..a1380fa4d0 100644 --- a/cpp/bindings/qpid/perl/CMakeLists.txt +++ b/cpp/bindings/qpid/perl/CMakeLists.txt @@ -21,18 +21,25 @@ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/perl.i + PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") swig_add_module(cqpid_perl perl ${CMAKE_CURRENT_SOURCE_DIR}/perl.i) swig_link_libraries(cqpid_perl qpidmessaging qpidtypes qmf2 ${PERL_LIBRARY}) -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PERL_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") +include_directories(${PERL_INCLUDE_PATH} + ${qpid-cpp_SOURCE_DIR}/include + ${qpid-cpp_SOURCE_DIR}/bindings) ##---------------------------------- ## Install the complete Perl binding ##---------------------------------- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqpid_perl.so ${CMAKE_CURRENT_BINARY_DIR}/cqpid_perl.pm - DESTINATION ${PERL_ARCHLIB} + ${CMAKE_CURRENT_SOURCE_DIR}/qpid.pm + ${CMAKE_CURRENT_SOURCE_DIR}/LICENSE + ${CMAKE_CURRENT_SOURCE_DIR}/Makefile.PL + DESTINATION ${PERL_PFX_ARCHLIB} COMPONENT ${QPID_COMPONENT_CLIENT} ) diff --git a/cpp/bindings/qpid/perl/ChangeLog b/cpp/bindings/qpid/perl/ChangeLog new file mode 100644 index 0000000000..72685443b1 --- /dev/null +++ b/cpp/bindings/qpid/perl/ChangeLog @@ -0,0 +1,6 @@ +Version 0.22 (TBA): + * QPID-4466: qpid::messaging::Duration now supports multiplication + * QPID-4416: Messages with embedded nulls won't break on getContentPtr + * QPID-4505: Provides unit tests for Address, Duration and Message + * QPID-4504: Broke up the Per classes into separate source modules + * QPID-4580: Added perldoc markup to each source module diff --git a/cpp/bindings/qpid/perl/LICENSE b/cpp/bindings/qpid/perl/LICENSE new file mode 100644 index 0000000000..bc46b77047 --- /dev/null +++ b/cpp/bindings/qpid/perl/LICENSE @@ -0,0 +1,206 @@ +========================================================================= +== Apache License == +========================================================================= + + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/cpp/bindings/qpid/perl/Makefile.PL b/cpp/bindings/qpid/perl/Makefile.PL new file mode 100644 index 0000000000..7a4d7f03dc --- /dev/null +++ b/cpp/bindings/qpid/perl/Makefile.PL @@ -0,0 +1,13 @@ +#!/usr/bin/perl -w + +use strict; + +use ExtUtils::MakeMaker; +use Config; + +WriteMakefile( + NAME => 'cqpid_perl', + PREREQ_PM => {}, + LIBS => ["-lqpidmessaging -lqpidtypes"], + C => ['cqpid_perl.cpp'], +); diff --git a/cpp/bindings/qpid/perl/README b/cpp/bindings/qpid/perl/README new file mode 100644 index 0000000000..ca5a96e539 --- /dev/null +++ b/cpp/bindings/qpid/perl/README @@ -0,0 +1,15 @@ +Qpid Perl Language Bindings +=========================== + +How to get help +=============== + +You can use the perldoc command to display API help for working with Qpid. + + perldoc qpid_messaging.pm + +will show a simple example application written in Perl that uses the APIs. +From there you can display the individual module documentation by typing: + + perldoc [module] + diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Address.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Address.pm new file mode 100644 index 0000000000..d417770b1c --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Address.pm @@ -0,0 +1,338 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Address + +=head1 DESCRIPTION + +An B<Address> represents an address to which messages can be sent or +from which they can be received. + +=head2 THE ADDRESS STRING + +An address can be described suing the following pattern: + +E<lt>addressE<gt> [ / E<lt>subjectE<gt> ]= ; [ { E<lt>keyE<gt> : E<lt>valueE<gt> , ... } ] + +where B<address> is a simple name and B<subject> is a subject or subject +pattern. + +=head3 ADDRESS OPTIONS + +The options, encluded in curly braces, are key:value pairs delimited by a comma. +The values can be nested maps also enclosed in curly braces. Or they can be +lists of values, where they are contained within square brackets but still comma +delimited, such as: + + [value1,value2,value3] + +The following are the list of supported options: + +=over + +=item B<create> + +Indicates if the address should be created; values are B<always>, B<never>, +B<sender> or B<receiver> + +=item B<assert> + +Indicates whether or not to assert any specified node properties; values are +B<always>, B<never>, B<sender> or B<receiver> + +=item B<delete> + +Indicates whether or not to delete the addressed node when a sender or receiver +is cancelled; values are B<always>, B<never>, B<sender> or B<receiver> + +=item B<node> + +A nested map describing properties for the addressed node. Properties are +B<type> (B<topic> or B<queue>), B<durable> (a boolean), B<x-declare> (a nested +map of AMQP 0.10-specific options) and B<x-bindings> (a nested list which +specifies a queue, exchange or a binding key and arguments). + +=item B<link> + +=item B<mode> + +=back + +=cut + +package qpid::messaging::Address; + +use overload ( + 'bool' => \& boolify, + '""' => \& stringify, + ); + +sub boolify { + my ($self) = @_; + my $impl = $self->{_impl}; + + return length($impl->getName()); +} + +sub stringify { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $self->str(); +} + +sub str { + my ($self) = @_; + + return $self->get_implementation()->str(); +} + +=pod + +=head1 CONSTRUCTOR + +Creates an B<Address> + +=over + +=item $address = new qpid::messaging::Address( addr ) + +=back + +=head3 ARGUMENTS + +=over + +=item * addr + +The address string. + +=back + +=cut +sub new { + my ($class) = @_; + my ($self) = {}; + + # 2 args: either a string address or a cqpid_perl::Address + # 3+ args: name + subject + options + type + if (@_ eq 2) { + my $address = $_[1]; + + if (ref($address) eq 'cqpid_perl::Address') { + $self->{_impl} = $address; + } else { + $self->{_impl} = new cqpid_perl::Address($_[1]); + } + } elsif (@_ >= 4) { + my $impl = new cqpid_perl::Address($_[1], $_[2], $_[3]); + + $impl->setType($_[4]) if @_ >= 5; + + $self->{_impl} = $impl; + } else { + die "You must specify an address." + } + + bless $self, $class; + return $self; +} + +sub get_implementation { + my ($self) = @_; + return $self->{_impl}; +} + +=pod + +=head1 ATTRIBUTES + +=cut + +=pod + +=head2 NAME + +The name portion of the address. + +=over + +=item $address->set_name( name ) + +=item $name = $address->get_name + +=back + +=head3 ARGUMENTS + +=over + +=item * name + +See the address string explanation. + +=back + +=cut +sub set_name { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->setName($_[1]); +} + +sub get_name { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getName(); +} + +=pod + +=head2 SUBJECT + +The subject portion of the address. + +=over + +=item $address->set_subject( subject ) + +=item $subject = $address->get_subject + +=back + +=head3 ARGUMENTS + +=over + +=item * subject + +See the address string explanation. + +=back + +=cut +sub set_subject { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->setSubject($_[1]); +} + +sub get_subject { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getSubject; +} + +=pod + +=head2 OPTIONS + +The address options. + +=over + +=item $address->set_options( options ) + +=item @opts = $address->get_options + +=back + +=head3 ARGUMENTS + +=over + +=item * options + +The set of name:value pairs for the address. See the address string explanation. + +=back + +=cut +sub set_options { + my ($self) = @_; + my $impl = $self->{_impl}; + my $options = $_[1]; + + die "Options cannot be null" if !defined($options); + + $impl->setOptions($_[1]); +} + +sub get_options { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getOptions; +} + +=pod + +=head2 TYPE + +The type of the address determines how B<Sender> and B<Receiver> objects are +constructed for it. It also affects how a b<reply-to> address is encoded. + +If no type is specified then it willb e determined by querying the broker. +Explicitly setting the type prevents this. + +=over + +=item $address->set_type( type ) + +=item $type = $address->get_type + +=back + +=head3 ARGUMENTS + +=over + +=item * type + +Values can be either B<queue> or B<type>. + +=back + +=cut +sub set_type { + my ($self) = @_; + my $impl = $self->{_impl}; + my $type = $_[1]; + + die "Type must be defined" if !defined($type); + + $impl->setType($type); +} + +sub get_type { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getType; +} + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Connection.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Connection.pm new file mode 100644 index 0000000000..6d478cdf0c --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Connection.pm @@ -0,0 +1,291 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Connection + +=head1 DESCRIPTION + +A B<qpid::messaging::Connection> represents a network connection to a remote +endpoint. + +=cut + +package qpid::messaging::Connection; + +=pod + +=head1 CONSTRUCTOR + +=over + +=item $conn = new qpid::messaging::Connection + +=item $conn = new qpid::messaging::Connection( url ) + +=item $conn = new qpid::messaging::Connection( url, options ) + +Creates a connection object. Raises a C<MessagingError> if an invalid +connection option is used. + +=back + +=head3 ARGUMENTS + +=over + +=item * url + +The URL for the broker. See B<qpid::messaging::Address> for more on + address strings + +=item * options + +The connection options. + +=back + +=cut + +sub new { + my ($class) = @_; + my $self = { + _url => $_[1] || "localhost:5672", + _options => $_[2] || {}, + _impl => $_[3], + }; + + bless $self, $class; + return $self; +} + +=pod + +=head1 ACTIONS + +=cut + + +=pod + +=head2 OPENING AND CLOSING CONNECTIONS + +=cut + + +=pod + +=over + +=item $conn->open + +Establishes the connection to the broker. + +=back + +=cut +sub open { + my ($self) = @_; + my $impl = $self->{_impl}; + + # if we have an implementation instance then use it, otherwise + # create a new implementation instance + unless (defined($impl)) { + my $url = $self->{_url}; + my ($options) = $self->{_options}; + + $impl = new cqpid_perl::Connection($url, $options); + $self->{_impl} = $impl + } + + $impl->open() unless $impl->isOpen() +} + +=pod + +=over + +=item $conn->is_open + +Reports whether the connection is open. + +=back + +=cut +sub is_open { + my ($self) = @_; + my $impl = $self->{_impl}; + + if (defined($impl) && $impl->isOpen()) { + 1; + } else { + 0; + } +} + +=pod + +=over + +=item $conn->close + +Closes the connection. + +=back + +=cut +sub close { + my ($self) = @_; + + if ($self->is_open) { + my $impl = $self->{_impl}; + + $impl->close; + $self->{_impl} = undef; + } +} + +=pod + +=head2 SESSIONS + +=cut + + +=pod + +=over + +=item $session = $conn->create_session + +=item $conn->create_session( name ) + +Creates a new session. + +=back + +=head3 ARGUMENTS + +=over + +=item * name + +Specifies a name for the session. + +=back + +=cut +sub create_session { + my ($self) = @_; + + die "No connection available." unless ($self->open); + + my $impl = $self->{_impl}; + my $name = $_[1] || ""; + my $session = $impl->createSession($name); + + return new qpid::messaging::Session($session, $self); +} + +=pod + +=over + +=item $session = $conn->create_transactional_session + +=item $session = $conn->create_transaction_session( name ) + +Creates a transactional session. + +=back + +=head3 ARGUMENTS + +=over + +=item * name + +Specifies a name for the session. + +=back + +=cut +sub create_transactional_session { + my ($self) = @_; + + die "No connection available." unless ($self->open); + + my $impl = $self->{_impl}; + my $name = $_[1] || ""; + my $session = $impl->createTransactionalSession($name); + + return new qpid::messaging::Session($session, $self); +} + +=pod + +=over + +=item $session = $conn->get_session( name ) + +Returns the session with the specified name. + +=over + +=item $name + +The name given to the session when it was created. + +=back + +=back + +=cut +sub get_session { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getSession($_[1]); +} + +=pod + +=over + +=item $uname = $conn->get_authenticated_username + +Returns the username user to authenticate with the broker. + +If the conneciton did not use authentication credentials, then the +username returned is "anonymous". + +=back + +=cut +sub get_authenticated_username { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getAuthenticatedUsername; +} + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Duration.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Duration.pm new file mode 100644 index 0000000000..7d05daeeab --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Duration.pm @@ -0,0 +1,204 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Duration + +=head1 DESCRIPTION + +A B<qpid::messaging::Duration> represents a period of time in milliseconds. + +=head1 NAMED DURATIONS + +The following named durations are available as constants + +=over + +=item B<FOREVER> + +The maximum wait time, equal to the maximum integer value for the platform. +Effective this will wait forever. + +=item B<IMMEDIATE> + +An alias for 0 milliseconds. + +=item B<SECOND> + +An alias for 1,000 milliseconds. + +=item B<MINUTE> + +An alias for 60,000 milliseconds. + +=back + +=cut + +package qpid::messaging::Duration; + +=pod + +=head1 OPERATORS + +=cut + +use overload ( + "*" => \&multiply, + "==" => \&equalify, + "!=" => \&unequalify, + ); + +=pod + +=over + +=item $doubled = $duration * $factor + +=item $doubled = $duration * 2 + +Multiplies the duration and returns a new instance. + +=over + +=item $factor + +A factor for multiplying the duration. + +=back + +=back + +=cut +sub multiply { + my ($self) = @_; + my $factor = $_[1]; + + die "Factor must be non-negative values" if !defined($factor) || ($factor < 0); + + my $duration = $self->{_impl} * $factor; + + return new qpid::messaging::Duration($duration); +} + +sub equalify { + my ($self) = @_; + my $that = $_[1]; + + return 0 if !defined($that) || !UNIVERSAL::isa($that, 'qpid::messaging::Duration');; + + return ($self->get_milliseconds() == $that->get_milliseconds()) ? 1 : 0; +} + +sub unequalify { + my ($self) = @_; + my $that = $_[1]; + + return 1 if !defined($that) || !UNIVERSAL::isa($that, 'qpid::messaging::Duration');; + + return ($self->get_milliseconds() != $that->get_milliseconds()) ? 1 : 0; +} + +=pod + +=head1 CONSTRUCTOR + +Creates a new instance. + +=over + +=item duration = new qpid::messaging::Duration( time ) + +=back + +=head3 ARGUMENTS + +=over + +=item * time + +The duration in B<milliseconds>. + +=back + +=cut +sub new { + my ($class) = @_; + my $duration = $_[1]; + + die "Duration time period must be defined" if !defined($duration); + + if (!UNIVERSAL::isa($duration, 'cqpid_perl::Duration')) { + die "Duration must be non-negative" if $duration < 0; + $duration = new cqpid_perl::Duration($duration); + } + + my ($self) = { + _impl => $duration, + }; + + bless $self, $class; + return $self; +} + +=pod + +=head1 ATTRIBUTES + +=cut + + +=pod + +=head2 MILLISECONDS + +The length of time is measured in milliseconds. + +=over + +=item time = $duration->get_milliseconds + +=back + +=cut +sub get_milliseconds { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getMilliseconds(); +} + +sub get_implementation { + my ($self) = @_; + + return $self->{_impl}; +} + +# TODO: Need a better way to define FOREVER +use constant { + FOREVER => new qpid::messaging::Duration(1000000), + IMMEDIATE => new qpid::messaging::Duration(0), + SECOND => new qpid::messaging::Duration(1000), + MINUTE => new qpid::messaging::Duration(60000), +}; + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Message.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Message.pm new file mode 100644 index 0000000000..6437290244 --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Message.pm @@ -0,0 +1,584 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Message + +=head1 DESCRIPTION + +A B<qpid::messaging::Message> a routable piece of information. + +=cut + +package qpid::messaging::Message; + + +=pod + +=head1 CONSTRUCTOR + +Creates a B<Message>. + +=over + +=item $msg = new qpid::messaging::Message + +=item $msg = new qpid::messaging::Message( $content ) + +=back + +=head3 ARGUMENTS + +=over + +=item * $content + +The message's content. + +=back + +=cut +sub new { + my ($class) = @_; + my $content = $_[1] if (@_ > 1); + my $impl = $_[2] if (@_ > 2); + my ($self) = { + _content => $content || "", + _impl => $impl || undef, + }; + + unless (defined($self->{_impl})) { + my $impl = new cqpid_perl::Message($self->{_content}); + + $self->{_impl} = $impl; + } + + bless $self, $class; + return $self; +} + +sub get_implementation { + my ($self) = @_; + + return $self->{_impl}; +} + + +=pod + +=head1 ATTRIBUTES + +=cut + +=pod + +=head2 REPLY TO ADDRESS + +The reply-to address tells a receiver where to send any responses. + +=over + +=item $msg->set_reply_to( "#reqly-queue;{create:always}" ) + +=item $msg->set_reply_to( address ) + +=item $address = $msg->get_reply_to + +=back + +=head3 ARGUMENTS + +=over + +=item * address + +The address. Can be either an instance of B<qpid::messaging::Address> or else an +address string. + +=back + +=cut +sub set_reply_to { + my ($self) = @_; + my $impl = $self->{_impl}; + my $address = $_[1]; + + # if the address was a string, then wrap it + # in a qpid::messaging::Address instance + if (!UNIVERSAL::isa($address, 'qpid::messaging::Address')) { + $address = new qpid::messaging::Address($_[1]); + } + + $impl->setReplyTo($address->get_implementation()); +} + +sub get_reply_to { + my ($self) = @_; + my $impl = $self->{_impl}; + + return new qpid::messaging::Address($impl->getReplyTo()); +} + +=pod + +=head2 SUBJECT + +=over + +=item $msg->set_subject( "responses" ) + +=item $msg->set_subject( subject ) + +=item $subject = $msg->get_subject + +=back + +=cut +sub set_subject { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->setSubject($_[1]); +} + +sub get_subject { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getSubject; +} + +=pod + +=head2 CONTENT TYPE + +This should be set by the sending application and indicates to the +recipients of the message how to interpret or decide the content. + +By default, only dictionaries and maps are automatically given a content +type. If this content type is replaced then retrieving the content will +not behave correctly. + +=over + +=item $msg->set_content_type( content_type ) + +=back + +=head3 ARGUMENTS + +=over + +=item * content_type + +The content type. For a list this would be C<amqp/list> and for a hash it is +C<amqp/map>. + +=back + +=cut +sub set_content_type { + my ($self) = @_; + my $type = $_[1]; + + my $impl = $self->{_impl}; + $impl->setContentType($type); +} + +sub get_content_type { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getContentType; +} + +=pod + +=head2 MESSAGE ID + +A message id must be a UUID type. A non-UUID value will be converted +to a zero UUID, thouygh a blank ID will be left untouched. + +=over + +=item $msg->set_message_id( id ) + +=item $id = $msg->get_message_id + +=back + +=cut +sub set_message_id { + my ($self) = @_; + my $impl = $self->{_impl}; + my $id = $_[1]; + + die "message id must be defined" if !defined($id); + + $impl->setMessageId($id); +} + +sub get_message_id { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getMessageId; +} + +=pod + +=head2 USER ID + +The user id should, in general, be the user-id which was used when +authenticating the connection itself, as the messaging infrastructure +will verify this. + +See B<qpid::messaging::Address#authenticated_username>. + +=over + +=item $msg->set_user_id( id ) + +=item $id = $msg->get_user_id + +=back + +=cut +sub set_user_id { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->setUserId($_[1]); +} + +sub get_user_id { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getUserId; +} + +=pod + +=head2 CORRELATION ID + +The correlation id can be used as part of a protocol for message exchange +patterns; e.g., a request-response pattern might require the correlation id +of the request and hte response to match, or it might use the message id of +the request as the correlation id on the response. + +B<NOTE:> If the id is not a string then the id is setup using the object's +string representation. + +=over + +=item $msg->set_correlation_id( id ) + +=item $id = $msg->get_correlation_id + +=back + +=cut +sub set_correlation_id { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->setCorrelationId($_[1]); +} + +sub get_correlation_id { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getCorrelationId; +} + +=pod + +=head2 PRIORITY + +The priority may be used by the messaging infrastructure to prioritize +delivery of messages with higher priority. + +B<NOTE:> If the priority is not an integer type then it is set using the +object's integer represtation. If the integer value is greater than an +8-bit value then only 8-bits are used. + +=over + +=item $msg->set_priority( priority ) + +=item $priority = $msg->get_priority + +=back + +=cut +sub set_priority { + my ($self) = @_; + my $impl = $self->{_impl}; + my $priority = $_[1]; + + die "Priority must be provided" if !defined($priority); + + $priority = int($priority); + die "Priority must be non-negative" if $priority < 0; + + $impl->setPriority($priority); +} + +sub get_priority { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getPriority; +} + +=pod + +=head2 TIME TO LIVE + +This can be used by the messaging infrastructure to discard messages +that are no longer of relevance. + +=over + +=item $msg->set_ttl( ttl ) + +=item $ttl = $msg->get_ttl + +=back + +=head3 ARGUMENTS + +=over + +=item * ttl + +A B<qpid::messaging::Duration> instance. If it is not, then a new instance +is created using the integer value for the argument. + +A B<negative> value is treated as the equipment of +B<qpid::messaging::Duration::FOREVER>. + +=back + +=cut +sub set_ttl { + my ($self) = @_; + my $impl = $self->{_impl}; + my $duration = $_[1]; + + die "Duration must be provided" if !defined($duration); + if (!UNIVERSAL::isa($duration, 'qpid::messaging::Duration')) { + $duration = int($duration); + + if ($duration < 0) { + $duration = qpid::messaging::Duration::FOREVER; + } elsif ($duration == 0) { + $duration = qpid::messaging::Duration::IMMEDIATE; + } else { + $duration = new qpid::messaging::Duration(int($duration)); + } + } + + $impl->setTtl($duration->get_implementation()); +} + +sub get_ttl { + my ($self) = @_; + my $impl = $self->{_impl}; + + return new qpid::messaging::Duration($impl->getTtl); +} + +=pod + +=head2 DURABILITY + +The durability of a B<Message> is a hint to the messaging infrastructure that +the message should be persisted or otherwise stored. This helps to ensure that +the message is not lost due to failures or a shutdown. + +=over + +=item $msg->set_durable( 1 ) + +=item $durable = $msg->get_durable + +=back + +=cut +sub set_durable { + my ($self) = @_; + my $impl = $self->{_impl}; + my $durable = $_[1]; + + die "Durable must be specified" if !defined($durable); + + $impl->setDurable($durable); +} + +sub get_durable { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getDurable; +} + +=pod + +=head2 REDELIVERED + +This is a hint to the messaging infrastructure that if de-duplication is +required, that this message should be examined to determine if it is a +duplicate. + +=over + +=item $msg->set_redelivered( 1 ) + +=item $redelivered = $msg->get_redelivered + +=back + +=cut +sub set_redelivered { + my ($self) = @_; + my $impl = $self->{_impl}; + my $redelivered = $_[1]; + + die "Redelivered must be specified" if !defined($redelivered); + + $impl->setRedelivered($redelivered); +} + +sub get_redelivered { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getRedelivered; +} + +=pod + +=head2 PROPERTIES + +Named properties for the message are name/value pairs. + +=over + +=item $msg->set_property( name, value ) + +=item $value = $msg->get_property( name ) + +=item @props = $msg->get_properties + +=back + +=head3 ARGUMENTS + +=over + +=item * name + +The property name. + +=item * value + +The property value. + +=back + +=cut +sub set_property { + my ($self) = @_; + my $impl = $self->{_impl}; + my $key = $_[1]; + my $value = $_[2]; + + $impl->setProperty($key, $value); +} + +sub get_properties { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getProperties; +} + +=pod + +=head2 CONTENT + +The message content. + +=begin _private + +TODO: Need to make the content automatically encode and decode for +hashes and lists. + +=end _private + +=over + +=item $msg->set_content( content ) + +=item $content = $msg->get_content + +=item $length = $msg->get_content_size + +=back + +=cut +sub set_content { + my ($self) = @_; + my $content = $_[1]; + my $impl = $self->{_impl}; + + die "Content must be provided" if !defined($content); + + $self->{_content} = $content; + + qpid::messaging::encode($content, $self); +} + +sub get_content { + my ($self) = @_; + my $impl = $self->{_impl}; + $content = $self->{_content} || undef; + + if(!defined($content)) { + $content = qpid::messaging::decode($self); + $self->{_content} = $content; + } + + return $content; +} + +sub get_content_size { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getContentSize; +} + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Receiver.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Receiver.pm new file mode 100644 index 0000000000..c3bc4bb8a8 --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Receiver.pm @@ -0,0 +1,317 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Receiver + +=head1 DESCRIPTION + +A B<qpid::messaging::Receiver> is the entity though which messages are received. + +An instance can only be created using an active (i.e., not previously closed) +B<qpid::messaging::Session>. + +=head1 EXAMPLE + + # create a connection and a session + my $conn = new qpid::messaging::Connection("mybroker:5672"); + conn->open; + my $session = $conn->create_session; + + # create a receiver that listens on the "updates" topic of "alerts" + my $recv = $session->create_receiver("alerts/updates"); + + # set the local queue size to hold a maximum of 100 messages + $recv->set_capacity(100); + + # wait for an incoming message and process it + my $incoming = $recv->get; + process($incoming) + +=cut + +package qpid::messaging::Receiver; + +sub new { + my ($class) = @_; + my ($self) = { + _impl => $_[1], + _session => $_[2], + }; + + die "Must provide an implementation." unless defined($self->{_impl}); + die "Must provide a Session." unless defined($self->{_session}); + + bless $self, $class; + return $self; +} + +=pod + +=head1 ACTIONS + +=cut + + +=pod + +There are two ways to retrieve messages: from the local queue or from the +remote queue. + +=head2 GETTING FROM THE LOCAL QUEUE + +Messages can be held locally in message queues. + +=over + +=item $incoming = $receiver->get + +=item $incoming = $receiver->get( timeout) + +=back + +=head3 ARGUMENTS + +=over + +=item * timeout + +The period of time to wait for a message before raising an exception. If no +period of time is specified then the default is to wait B<forever>. + +=back + +=cut +sub get { + my ($self) = @_; + my $duration = $_[1]; + my $impl = $self->{_impl}; + + $duration = $duration->get_implementation() if defined($duration); + + my $message = undef; + + if (defined($duration)) { + $message = $impl->get($duration); + } else { + $message = $impl->get; + } +} + +=pod + +=head2 FETCHING FROM THE REMOTE QUEUE + +Messages held in the remote queue must be fetched from the broker in order +to be processed. + +=over + +=item $incoming = $receiver->fetch + +=item $incoming = $receiver->fetch( time ) + +=back + +=head3 ARGUMENTS + +=over + +=item * timeout + +The period of time to wait for a message before raising an exception. If no +period of time is specified then the default is to wait B<forever>. + +=back + +=cut +sub fetch { + my ($self) = @_; + my $duration = $_[1]; + my $impl = $self->{_impl}; + my $message = undef; + + if (defined($duration)) { + $message = $impl->fetch($duration->get_implementation()); + } else { + $message = $impl->fetch; + } + + return new qpid::messaging::Message("", $message); +} + +=pod + +=head2 CLOSING THE RECEIVER + +=over + +=item receiver->close + +Closes the receiver. + +=back + +=cut +sub close { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->close; +} + +=pod + +=head1 ATTRIBUTES + +=cut + + +=pod + +=head2 CAPACITY + +The maximum number of messages that are prefected and held locally is +determined by the capacity of the receiver. + +=over + +=item $receiver->set_capacity( size ) + +=item $size = $receiver->get_capacity + +=back + +=cut +sub set_capacity { + my ($self) = @_; + my $capacity = $_[1]; + my $impl = $self->{_impl}; + + $impl->setCapacity($capacity); +} + +sub get_capacity { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getCapacity; +} + +=pod + +=head2 AVAILABLE + +The number of messages waiting in the local queue. + +The value is always in the range 0 <= B<available> <= B<capacity>. + +=over + +=item $count = $receiver->get_available + +=back + +=cut + +sub get_available { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getAvailable; +} + +=pod + +=over + +=item $count = $receiver->get_unsettled + +Returns the number of messages that have been received and acknowledged but +whose acknowledgements have not been confirmed by the sender. + +=back + +=cut +sub get_unsettled { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getUnsettled; +} + +=pod + +=over + +=item $name = $receiver->get_name + +Returns the name of the receiver. + +=back + +=cut +sub get_name { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getName; +} + +=pod + +=over + +=item $session = $receiver->get_session + +Returns the B<qpid::messaging::Session> instance from which this +receiver was created. + +=back + +=cut +sub get_session { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->{_session}; +} + +=pod + +=over + +=item $receiver->is_closed + +Returns whether the receiver is closed. + +=back + +=cut +sub is_closed { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->isClosed; +} + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Sender.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Sender.pm new file mode 100644 index 0000000000..5d0896ff79 --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Sender.pm @@ -0,0 +1,258 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Sender + +=head1 DESCRIPTION + +A B<qpid::messaging::Sender> is the entity through which messages are sent. + +An instance can only be created using an active (i.e., not previously closed) +B<qpid::messaging::Session>. + +=head1 EXAMPLE + + # create a connection and a session + my $conn = new qpid::messaging::Connection("mybroker:5672"); + conn->open; + my $session = $conn->create_session; + + # create a sender that posts messages to the "updates" queue + my $sender = $session->create_sender "updates;{create:always}" + + # begin sending updates + while( 1 ) { + my $content = wait_for_event; + $sender->send(new qpid::messaging::Message($content)); + } + +=cut + +package qpid::messaging::Sender; + +sub new { + my ($class) = @_; + my ($self) = { + _impl => $_[1], + _session => $_[2], + }; + + die "Must provide an implementation." unless defined($self->{_impl}); + die "Must provide a Session." unless defined($self->{_session}); + + bless $self, $class; + return $self; +} + +=pod + +=head1 ACTIONS + +=cut + + +=pod + +=head2 SENDING MESSAGES + +=over + +=item $sender->send( message ) + +=item $sender->send( message, block) + +Sends a message, optionally blocking until the message is received by +the broker. + +=back + +=head3 ARGUMENTS + +=over + +=item * message + +The message to be sent. + +=item * block + +If true then blocks until the message is received. + +=back + +=cut +sub send { + my ($self) = @_; + my $message = $_[1]; + my $sync = $_[2] || 0; + + die "No message to send." unless defined($message); + + my $impl = $self->{_impl}; + + $impl->send($message->get_implementation, $sync); +} + +=pod + +=head2 CLOSING THE SENDER + +=item sender->close + +Closes the sender. + +This does not affect the ownering B<Session> or B<Connection> + +=back + +=cut +sub close { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->close; +} + +=pod + +=head1 ATTRIBUTES + +=cut + +=pod + +=head2 CAPACITY + +The capacity is the number of outoing messages that can be held pending +confirmation of receipt by the broker. + +=over + +=item sender->set_capacity( size ) + +=item $size = sender->get_capacity + +=back + +=back + +=cut +sub set_capacity { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->setCapacity($_[1]); +} + +sub get_capacity { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getCapacity; +} + +=pod + +=head2 UNSETTLED + +The number of messages sent that are pending receipt confirmation by the broker. + +=over + +=item $count = sender->get_unsettled + +=back + +=cut +sub get_unsettled { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getUnsettled; +} + +=pod + +=head2 AVAILABLE + +The available slots for sending messages. + +This differences form B<capacity> in that it is the available slots in the +senders capacity for holding outgoing messages. The difference between +capacity and available is the number of messages that have no been delivered +yet. + +=over + +=item $slots = sender->get_available + +=back + +=cut +sub get_available { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getAvailable(); +} + +=pod + +=head2 NAME + +The human-readable name for this sender. + +=over + +=item $name = sender-get_name + +=back + +=cut +sub get_name { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getName; +} + +=pod + +=head2 SESSION + +The owning session from which the sender was created. + +=over + +=item $session = $sender->get_session + +=back + +=cut +sub get_session { + my ($self) = @_; + + return $self->{_session}; +} + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/Session.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/Session.pm new file mode 100644 index 0000000000..af85731685 --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/Session.pm @@ -0,0 +1,473 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +=pod + +=head1 NAME + +qpid::messaging::Session + +=head1 DESCRIPTION + +A B<qpid::messaging::Session> represents a distinct conversation between end +points. They are created from an active (i.e, not closed) B<Connection>. + +A session is used to acknowledge individual or all messages that have +passed through it, as well as for creating senders and receivers for conversing. +=cut +package qpid::messaging::Session; + +sub new { + my ($class) = @_; + my ($self) = { + _impl => $_[1], + _conn => $_[2], + }; + + die "Must provide an implementation." unless defined($self->{_impl}); + die "Must provide a Connection." unless defined($self->{_conn}); + + bless $self, $class; + return $self; +} + +=pod + +=head1 ACTIONS + +=cut + + +=pod + +=head2 CLOSING THE SESSION + +=over + +=item $session->close + +=back + +=cut +sub close { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->close; +} + +=pod + +=head2 TRANSACTIONS + +Transactions can be rolled back or committed. + +=over + +=item $session->commit + +=item $session->rollback + +=back + +=cut +sub commit { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->commit; +} + +sub rollback { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->rollback; +} + +=pod + +=head2 MESSAGE DISPOSITIONS + +=cut + + +=pod + +=over + +=item $session->acknowledge( msg ) + +Acknowledges that a specific message that has been received. + +=back + +=begin _private + +TODO: How to handle acknowledging a specific message? + +=end _private + +=cut +sub acknowledge { + my ($self) = @_; + my $sync = $_[1] || 0; + + my $impl = $self->{_impl}; + + $impl->acknowledge($sync); +} + +=pod + +=over + +=item $session->reject( msg ) + +Rejects the specified message. A reject message will not be redelivered. + +=back + +=cut +sub reject { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->reject($_[1]); +} + +=pod + +=over + +=item $session->release( msg ) + +Releases the specified message, which allows the broker to attempt to +redeliver it. + +=back + +=cut +sub release { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->release($_[1]); +} + +=pod + +=over + +=item $session->sync + +=item $session->sync( block ) + +Requests synchronization with the broker. + +=back + +=head3 ARGUMENTS + +=over + +=item * block + +If true, then the call blocks until the process completes. + +=back + +=cut +sub sync { + my ($self) = @_; + my $impl = $self->{_impl}; + + if(defined($_[1])) { + $impl->sync($_[1]); + } else { + $impl->sync; + } +} + +=pod + +=head2 SENDERS AND RECEIVERS + +=cut + + +=pod + +=over + +=item $sender = $session->create_sender( address ) + +Creates a new sender. + +=back + +=head3 ARGUMENTS + +=over + +=item * address + +The sender address. See B<qpid::messaging::Address> for more details + +=back + +=cut +sub create_sender { + my ($self) = @_; + my $impl = $self->{_impl}; + + my $address = $_[1]; + + if (ref($address) eq "qpid::messaging::Address") { + my $temp = $address->get_implementation(); + $address = $temp; + } + my $send_impl = $impl->createSender($address); + + return new qpid::messaging::Sender($send_impl, $self); +} + +=pod + +=over + +=item $sender = $session->get_session( name ) + +=back + +=head3 ARGUMENTS + +=over + +=item * name + +The name of the sender. + +Raises an exception when no sender with that name exists. + +=back + +=cut +sub get_sender { + my ($self) = @_; + my $impl = $self->{_impl}; + + my $send_impl = $impl->getSender($_[1]); + my $sender = undef; + + if (defined($send_impl)) { + $sender = new qpid::messaging::Sender($send_impl, $self); + } + + return $sender; +} + +=pod + +=over + +=item $receiver = $session->create_receiver( address ) + +=back + +=head3 ARGUMENTS + +=over + +=item * address + +The receiver address. see B<qpid::messaging::Address> for more details. + +=back + +=cut +sub create_receiver { + my ($self) = @_; + my $impl = $self->{_impl}; + + my $address = $_[1]; + + if (ref($address) eq "qpid::messaging::Address") { + $address = $address->get_implementation(); + } + my $recv_impl = $impl->createReceiver($address); + + return new qpid::messaging::Receiver($recv_impl, $self); +} + +=pod + +=over + +=item $receiver = $session->get_receiver( name ) + +=back + +=head3 ARGUMENTS + +=over + +=item * name + +The name of the receiver. + +=back + +=cut +sub get_receiver { + my ($self) = @_; + my $impl = $self->{_impl}; + + my $recv_impl = $impl->getReceiver($_[1]); + my $receiver = undef; + + if (defined($recv_impl)) { + $receiver = new qpid::messaging::Receiver($recv_impl, $self); + } + + return $receiver; +} + +=pod + +=head1 ATTRIBUTES + +=cut + + +=pod + +=head2 RECEIVABLE + +The total number of receivable messages, and messages already received, +by receivers associated with this session. + +=over + +=item $session->get_receivable + +=back + +=cut +sub get_receivable { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getReceivable; +} + +=pod + +=head2 UNSETTLED ACKNOWLEDGEMENTS + +The number of messages that have been acknowledged by this session whose +acknowledgements have not been confirmed as processed by the broker. + +=over + +=item $session->get_unsettled_acks + +=back + +=cut +sub get_unsettled_acks { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->getUnsettledAcks; +} + +=pod + +=head2 NEXT RECEIVER + +The next receiver is the one, created by this session, that has any pending +local messages. + +If no receivers are found within the timeout then a B<MessagingException> is +raised. + +=over + +=item $session->get_next_receiver + +=item $session->get_next_receiver( timeout ) + +=back + +=head3 ARGUMENTS + +=over + +=item * timeout + +The period of time to wait for a receiver to be found. If no period of time is +specified then the default is to wait B<forever>. + +=back + +=cut +sub get_next_receiver { + my ($self) = @_; + my $impl = $self->{_impl}; + + my $timeout = $_[1] || qpid::messaging::Duration::FOREVER; + + return $impl->getNextReceiver($timeout); +} + +=pod + +=head2 CONNECTION + +=over + +=item $conn = $session->get_connection + +Returns the owning connection for the session. + +=back + +=cut +sub get_connection { + my ($self) = @_; + + return $self->{_conn}; +} + +sub has_error { + my ($self) = @_; + my $impl = $self->{_impl}; + + return $impl->hasError; +} + +sub check_for_error { + my ($self) = @_; + my $impl = $self->{_impl}; + + $impl->checkForError; +} + +1; diff --git a/cpp/bindings/qpid/perl/lib/qpid/messaging/codec.pm b/cpp/bindings/qpid/perl/lib/qpid/messaging/codec.pm new file mode 100644 index 0000000000..c9d6845eb9 --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid/messaging/codec.pm @@ -0,0 +1,53 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +package qpid::messaging; + +sub encode { + my $content = $_[0]; + my $message = $_[1]; + my $impl = $message->get_implementation(); + + if(UNIVERSAL::isa($content, "HASH")) { + cqpid_perl::encode($content, $impl, "amqp/map"); + } elsif(UNIVERSAL::isa($content, "ARRAY")) { + cqpid_perl::encode($content, $impl, "amqp/list"); + } else { + $message->get_implementation()->setContent($content); + } +} + +sub decode { + my $message = $_[0]; + my $impl = $message->get_implementation(); + my $content_type = $impl->getContentType(); + + if($content_type eq "amqp/map") { + $result = cqpid_perl::decodeMap($impl); + } elsif($content_type eq "amqp/list") { + $result = cqpid_perl::decodeList($impl); + } else { + $result = $impl->getContent(); + } + + return $result; +} + +1; + diff --git a/cpp/bindings/qpid/perl/lib/qpid_messaging.pm b/cpp/bindings/qpid/perl/lib/qpid_messaging.pm new file mode 100644 index 0000000000..e6a2681c15 --- /dev/null +++ b/cpp/bindings/qpid/perl/lib/qpid_messaging.pm @@ -0,0 +1,95 @@ +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +# + +use strict; +use warnings; +use cqpid_perl; + +package qpid::messaging; + +use qpid::messaging::codec; +use qpid::messaging::Address; +use qpid::messaging::Duration; +use qpid::messaging::Message; +use qpid::messaging::Receiver; +use qpid::messaging::Sender; +use qpid::messaging::Session; +use qpid::messaging::Connection; + +1; + +__END__ + +=pod + +=head1 NAME + +qpid::messaging + +=head1 DESCRIPTION + +The Qpid Messaging framework is an enterprise messaging framework +based on the open-source AMQP protocol. + +=head1 EXAMPLE + +Here is a simple example application. It creates a link to a broker located +on a system named C<broker.myqpiddomain.com>. It then creates a new messaging +queue named C<qpid-examples> and publishes a message to it. It then consumes +that same message and closes the connection. + + use strict; + use warnings; + + use qpid; + + # create a connection, open it and then create a session named "session1" + my $conn = new qpid::messaging::Connection("broker.myqpiddomain.com"); + $conn->open(); + my $session = $conn->create_session("session1"); + + # create a sender and a receiver + # the sender marks the queue as one that is deleted when the sender disconnects + my $send = $session->create_sender("qpid-examples;{create:always}"); + my $recv = $session->create_receiver("qpid-examples"); + + # create an outgoing message and send it + my $outgoing = new qpid::messaging::Message(); + $outgoing->set_content("The time is " . localtime(time)"); + $send->send($outgoing); + + # set the receiver's capacity to 10 and then check out many messages are pending + $recv->set_capacity(10); + print "There are " . $recv->get_available . " messages waiting.\n"; + + # get the nextwaitingmessage, which should be in the local queue now, + # and output the contents + my $incoming = $recv->fetch(); + print "Received the following message: " . $incoming->get_content() . "\n"; + # the output should be the text that was sent earlier + + # acknowledge the message, letting the sender know the message was received + printf "The sender currently has " . $send->get_unsettled . " message(s) pending.\n"; + # should report 1 unsettled message + $session->acknowledge(); # acknowledges all pending messages + print "Now sender currently has " . $send->get_unsettled . " message(s) pending.\n"; + # should report 0 unsettled messages + + # close the connection + $conn->close diff --git a/cpp/bindings/qpid/perl/perl.i b/cpp/bindings/qpid/perl/perl.i index 38ac91761f..0d118ae0fb 100644 --- a/cpp/bindings/qpid/perl/perl.i +++ b/cpp/bindings/qpid/perl/perl.i @@ -19,7 +19,7 @@ %module cqpid_perl %include "std_string.i" -%include "../../swig_perl_typemaps.i" +%include "qpid/swig_perl_typemaps.i" /* Define the general-purpose exception handling */ %exception { @@ -31,5 +31,5 @@ } } -%include "../qpid.i" +%include "qpid/qpid.i" diff --git a/cpp/bindings/qpid/ruby/lib/qpid/version.rb b/cpp/bindings/qpid/perl/qpid.pm index 39524e428f..88b98353a8 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/version.rb +++ b/cpp/bindings/qpid/perl/qpid.pm @@ -17,15 +17,6 @@ # under the License. # -module Qpid +use qpid_messaging; - module Version - - NUMBERS = [MAJOR = 0, - MINOR = 17, - BUILD = 0] - end - - VERSION = Version::NUMBERS.join('.') - -end +1; diff --git a/cpp/bindings/qpid/perl/t/Address.t b/cpp/bindings/qpid/perl/t/Address.t new file mode 100644 index 0000000000..4e74f8cad2 --- /dev/null +++ b/cpp/bindings/qpid/perl/t/Address.t @@ -0,0 +1,102 @@ +#!/usr/bin/env perl -w +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 Test::More qw(no_plan); +use Test::Exception; + +require 'utils.pm'; + +# verify that qpid is available +BEGIN { use_ok( 'qpid' ); } +require_ok ('qpid' ); + +# construction +# address cannot be null +dies_ok (sub {new qpid::messaging::Address(undef);}, + "Address cannot be null"); + +# can use an address +my $address = new qpid::messaging::Address("0.0.0.0"); +ok ($address, "Can be created with an arbitrary address"); + +# name +# name cannot be null +dies_ok (sub {$address->set_name(undef);}, + "Name cannot be null"); + +# name can be an empty string +$address->set_name(""); +ok ($address->get_name() eq "", + "Name can be empty"); + +# name can be an arbitrary string +my $name = random_string(25); +$address->set_name($name); +ok ($address->get_name() eq $name, + "Name can be an arbitrary string"); + +# subject +# cannot be null +dies_ok (sub {$address->set_subject(undef);}, + "Subject cannot be null"); + +# can be an empty string +$address->set_subject(""); +ok ($address->get_subject() eq "", + "Subject can be empty"); + +# can be an arbitrary string +my $subject = random_string(64); +$address->set_subject($subject); +ok ($address->get_subject() eq $subject, + "Subject can be an arbitrary string"); + +# options +# options cannot be null +dies_ok (sub {$address->set_options(undef);}, + "Options cannot be null"); + +# options can be an empty hash +$address->set_options({}); +ok (eq_hash($address->get_options(), {}), + "Options can be an empty hash"); + +# options cannot be arbitrary values +my %options = ("create", "always", "delete", "always"); +$address->set_options(\%options); +ok (eq_hash($address->get_options(), \%options), + "Options can be arbitrary keys"); + +# type +# cannot be null +dies_ok (sub {$address->set_type(undef);}, + "Type cannot be null"); + +# can be an empty string +$address->set_type(""); +ok ($address->get_type() eq "", + "Type can be an empty string"); + +# can be an arbitrary string +my $type = random_string(16); +$address->set_type($type); +ok ($address->get_type() eq $type, + "Type can be an arbitrary type"); + diff --git a/cpp/bindings/qpid/perl/t/Duration.t b/cpp/bindings/qpid/perl/t/Duration.t new file mode 100644 index 0000000000..6975e8006f --- /dev/null +++ b/cpp/bindings/qpid/perl/t/Duration.t @@ -0,0 +1,124 @@ +#!/usr/bin/env perl -w +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 Test::More qw(no_plan); +use Test::Exception; + +require 'utils.pm'; + +# verify that qpid is available +BEGIN { use_ok( 'qpid' ); } +require_ok ('qpid' ); + +# milliseconds +# duration cannot be null +{ + dies_ok (sub {new qpid::messaging::Duration(undef);}, + "Durations cannot have null time periods"); +} + +# duration cannot be negative +{ + my $period = 0 - (int(rand(65535)) + 1); + dies_ok(sub {new qpid::messaging::Duration($period);}, + "Duration times cannot be negative"); +} + +# duration can be an arbitrary value +{ + my $period = int(rand(65535)); + my $duration = new qpid::messaging::Duration($period); + ok ($duration->get_milliseconds() == $period, + "Milliseconds are properly stored and fetched"); +} + +# multiplier +# cannot multiply by null +dies_ok(sub {qpid::messaging::Duration::FOREVER * undef;}, + "Cannot multiply a duration times a null"); + +# cannot multiply by a negative +dies_ok (sub {qpid::messaging::Duration::MINUTE * -2;}, + "Duration cannot be multiplied by a negative"); + +# multiply by zero returns a zero time period +{ + my $result = qpid::messaging::Duration::MINUTE * 0; + + ok ($result->get_milliseconds() == 0, + "Multiplying duration by 0 returns a 0 duration"); +} + +# multiply by arbitrary values works +{ + my $factor = int(1 + rand(100)); + my $result = qpid::messaging::Duration::MINUTE * $factor; + ok ($result->get_milliseconds() == 60000 * $factor, + "Multiplying by a factor returns a new Duration with that period"); +} + +# equality +# always fails with null +ok (!(qpid::messaging::Duration::MINUTE == undef), + "Duration is never equal to null"); + +# never equal to a non-duration class +ok (!(qpid::messaging::Duration::MINUTE == random_string(12)), + "Duration is never equal to a non-Duration"); + +# works with self +ok (qpid::messaging::Duration::MINUTE == qpid::messaging::Duration::MINUTE, + "Duration is always equal to itself"); + +# fails with non-equal instance +ok (!(qpid::messaging::Duration::MINUTE == qpid::messaging::Duration::SECOND), + "Duration non-equality works"); + +# works with equal instance +{ + my $result = qpid::messaging::Duration::MINUTE * 0; + ok ($result == qpid::messaging::Duration::IMMEDIATE, + "Equality comparison works correctly"); +} + +# non-equality +# always not equal to null +ok (qpid::messaging::Duration::MINUTE != undef, + "Always unequal to null"); + +# always not equal to a non-duration class +ok (qpid::messaging::Duration::MINUTE != random_string(64), + "Always unequal to a non-duration class"); + +# not unequal to itself +ok (!(qpid::messaging::Duration::MINUTE != qpid::messaging::Duration::MINUTE), + "Never unequal to itself"); + +# not unequal to an equal instance +{ + my $duration = qpid::messaging::Duration::MINUTE * 1; + ok (!(qpid::messaging::Duration::MINUTE != $duration), + "Never unequal to an equal instance"); +} + +# works with unequal instances +ok (qpid::messaging::Duration::MINUTE != qpid::messaging::Duration::FOREVER, + "Always unequal to a non-equal instance"); + diff --git a/cpp/bindings/qpid/perl/t/Message.t b/cpp/bindings/qpid/perl/t/Message.t new file mode 100644 index 0000000000..15baafb446 --- /dev/null +++ b/cpp/bindings/qpid/perl/t/Message.t @@ -0,0 +1,286 @@ +#!/usr/bin/env perl -w +# +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 Test::More qw(no_plan); +use Test::Exception; + +require 'utils.pm'; + +# verify that qpid is available +BEGIN { use_ok( 'qpid' ); } +require_ok ('qpid' ); + +# Create a new message +my $message = new qpid::messaging::Message(); +isa_ok($message, 'qpid::messaging::Message'); + +# reply to +# rejects an null address +dies_ok (sub {$message->set_reply_to(undef);}, + "Reply to cannot be null."); + +# can handle a string address +$message->set_reply_to("test"); +ok ($message->get_reply_to()->str() eq "test", + "Reply to can be set"); + +# subject +# cannot have an null subject +dies_ok (sub {$message->set_subject(undef);}, + "Subject cannot be null"); + +# can have an empty subject +$message->set_subject(""); +ok ($message->get_subject() eq "", + "Subject can be empty"); + +# can have a subject +my $subject = random_string(16); +$message->set_subject($subject); +ok ($message->get_subject() eq $subject, + "Subject can be set."); + +# content type +# cannot have an null content type +dies_ok (sub {$message->set_content_type(undef);}, + "Content type must be defined."); + +# can an empty content type +$message->set_content_type(""); +ok ($message->get_content_type() eq "", + "Content type can be empty"); + +# can have an arbitrary content type +my $content_type = random_string(10); +$message->set_content_type($content_type); +ok ($message->get_content_type() eq $content_type, + "Content type can be arbitrary"); + +# can be for a map +$content_type = "amqp/map"; +$message->set_content_type($content_type); +ok ($message->get_content_type() eq $content_type, + "Content type can be for a map"); + +# message id +# cannot be null +dies_ok (sub {$message->set_message_id(undef);}, + "Message id cannot be null"); + +# can be an empty string +$message->set_message_id(""); +ok ($message->get_message_id() eq "", + "Message id can be empty"); + +# can be an arbitrary string +my $id = random_string(32); +$message->set_message_id($id); +ok ($message->get_message_id() eq $id, + "Message id can be an arbitrary string"); + +# can be a UUID +$id = generate_uuid(); +$message->set_message_id($id); +ok ($message->get_message_id() eq $id, + "Message id can be a valid UUID"); + +# user id +# cannot be null +dies_ok (sub {$message->set_user_id(undef);}, + "User id cannot be null"); + +# can be an empty string +my $user_id = ""; +$message->set_user_id($user_id); +ok ($message->get_user_id() eq $user_id, + "User id can be empty"); + +# can be an arbitrary string +$id = random_string(65); +$message->set_user_id($user_id); +ok ($message->get_user_id() eq $user_id, + "User id can be an arbitrary string"); + +# correlation id +# cannot be null +dies_ok (sub {$message->set_correlation_id(undef);}, + "Correlation id cannot be null"); + +# can be empty +my $correlation_id = ""; +$message->set_correlation_id($correlation_id); +ok ($message->get_correlation_id() eq $correlation_id, + "Correlation id can be an empty string"); + +# can be an arbitrary string +$correlation_id = random_string(32); +$message->set_correlation_id($correlation_id); +ok ($message->get_correlation_id() eq $correlation_id, + "Correlation id can be an arbitrary string"); + +# priority +# cannot be nul +dies_ok (sub {$message->set_priority(undef);}, + "Priority cannot be null"); + +# cannot be negative +my $priority = 0 - (rand(2**8) + 1); +dies_ok (sub {$message->set_priority($priority);}, + "Priority cannot be negative"); + +# can be 0 +$message->set_priority(0); +ok ($message->get_priority() == 0, + "Priority can be zero"); + +# can be an arbitrary value +$priority = int(rand(2**8) + 1); +$message->set_priority($priority); +ok ($message->get_priority() == $priority, + "Priority can be any positive value"); + +# ttl +# cannot be null +dies_ok (sub {$message->set_ttl(undef);}, + "TTL cannot be null"); + +# can be a duration +$message->set_ttl(qpid::messaging::Duration::FOREVER); +ok ($message->get_ttl()->get_milliseconds() == qpid::messaging::Duration::FOREVER->get_milliseconds(), + "TTL can be a Duration"); + +# if numeric, is converted to a duration +my $duration = rand(65535); +$message->set_ttl($duration); +ok ($message->get_ttl()->get_milliseconds() == int($duration), + "TTL can be any arbitrary duration"); + +# if 0 it's converted to IMMEDIATE +$message->set_ttl(0); +ok ($message->get_ttl()->get_milliseconds() == qpid::messaging::Duration::IMMEDIATE->get_milliseconds(), + "TTL of 0 is converted to IMMEDIATE"); + +# if negative it's converted to FOREVER +$message->set_ttl(0 - (rand(65535) + 1)); +ok ($message->get_ttl()->get_milliseconds() == qpid::messaging::Duration::FOREVER->get_milliseconds(), + "TTL of <0 is converted to FOREVER"); + +# durable +# cannot be null +dies_ok (sub {$message->set_durable(undef);}, + "Durable cannot be null"); + +# can be set to true +$message->set_durable(1); +ok ($message->get_durable(), + "Durable can be true"); + +# can be set to false +$message->set_durable(0); +ok (!$message->get_durable(), + "Durable can be false"); + +# redelivered +# redelivered cannot be null +dies_ok (sub {$message->set_redelivered(undef);}, + "Redelivered cannot be null"); + +# can be set to true +$message->set_redelivered(1); +ok ($message->get_redelivered(), + "Redelivered can be true"); + +# can be set to false +$message->set_redelivered(0); +ok (!$message->get_redelivered(), + "Redelivered can be false"); + +# properties +# can retrieve all properties +my $properties = $message->get_properties(); +ok (UNIVERSAL::isa($properties, 'HASH'), + "Returns the properties as a hash map"); + +# property +# setting a property using a null key fails +dies_ok (sub {$message->set_property(undef, "bar");}, + "Property cannot have a null key"); + +# setting a property with a null value succeeds +my $key = random_string(16); +$message->set_property($key, undef); +ok (!$message->get_properties()->{$key}, + "Properties can have null values"); + +# setting a property succeeds +my $value = random_string(255); +$message->set_property($key, $value); +ok ($message->get_properties()->{$key} eq $value, + "Messages can have arbitrary property values"); + +# content +# cannot be null +dies_ok (sub {$message->set_content(undef);}, + "Content cannot be null"); + +# can be an empty string +$message->set_content(""); +ok ($message->get_content() eq "", + "Content can be an empty string"); + +# can be an arbitrary string +my $content = random_string(255); +$message->set_content($content); +ok ($message->get_content() eq $content, + "Content can be an arbitrary string"); + +# Embedded nulls should be handled properly +$content = { id => 1234, name => "With\x00null" }; +qpid::messaging::encode($content, $message); +my $map = qpid::messaging::decode_map($message); +ok ($map->{name} eq "With\x00null", + "Nulls embedded in map values work."); + +# Unicode strings shouldn't be broken +$content = { id => 1234, name => "Euro=\x{20AC}" }; +qpid::messaging::encode($content, $message); +$map = qpid::messaging::decode_map($message); +ok ($map->{name} eq "Euro=\x{20AC}", + "Unicode strings encoded correctly."); + +# Setting the content as a hash automatically encodes it +($content) = {"id" => "1234", "name" => "qpid"}; +$message->set_content($content); +ok ($message->get_content_type() eq "amqp/map", + "Hashes are automatically encoded correctly"); + +# Setting the content as a list automatically encodes it +my @acontent = (1, 2, 3, 4); +$message->set_content(\@acontent); +ok ($message->get_content_type() eq "amqp/list", + "Lists are automatically encoded correctly"); + +# content size +# content size is correct +my $content_size = int(rand(256)); +$content = random_string($content_size); +$message->set_content($content); +ok ($message->get_content_size() == $content_size, + "Content size is correct"); diff --git a/cpp/bindings/qpid/ruby/lib/qpid/errors.rb b/cpp/bindings/qpid/perl/t/utils.pm index c98eb1ac12..db8093d324 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/errors.rb +++ b/cpp/bindings/qpid/perl/t/utils.pm @@ -1,4 +1,3 @@ -# # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -17,17 +16,23 @@ # under the License. # -module Qpid - - module Messaging - - class KeyError < RuntimeError; end +use Digest::MD5; - class SessionNameException < Exception - def initialize(msg); super(msg); end - end +sub random_string +{ + my $len=$_[0]; + my @chars=('a'..'z','A'..'Z','0'..'9','_'); + my $result; - end + foreach (1..$len) { + $result .= $chars[rand @chars]; + } + return $result; +} -end +sub generate_uuid +{ + return Digest::MD5::md5_base64( rand ); +} +1; diff --git a/cpp/bindings/qpid/python/CMakeLists.txt b/cpp/bindings/qpid/python/CMakeLists.txt index 9cb40162a5..2693475dea 100644 --- a/cpp/bindings/qpid/python/CMakeLists.txt +++ b/cpp/bindings/qpid/python/CMakeLists.txt @@ -21,17 +21,20 @@ ## Use Swig to generate a literal binding to the C++ API ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES CPLUSPLUS ON) -set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/python.i + PROPERTIES SWIG_FLAGS "-I${qpid-cpp_SOURCE_DIR}/include;-I${qpid-cpp_SOURCE_DIR}/bindings") swig_add_module(cqpid_python python ${CMAKE_CURRENT_SOURCE_DIR}/python.i) swig_link_libraries(cqpid_python qpidmessaging qpidtypes qmf2 ${PYTHON_LIBRARIES}) -set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing -I${PYTHON_INCLUDE_PATH} -I${qpid-cpp_SOURCE_DIR}/include") +set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_FLAGS "-fno-strict-aliasing") +include_directories(${PYTHON_INCLUDE_PATH} + ${qpid-cpp_SOURCE_DIR}/include + ${qpid-cpp_SOURCE_DIR}/bindings) ##------------------------------------ ## Install the complete Python binding ##------------------------------------ -execute_process(COMMAND ${PYTHON_EXECUTABLE} -c "from distutils.sysconfig import get_python_lib; print get_python_lib()" OUTPUT_VARIABLE PYTHON_SITE_PACKAGES OUTPUT_STRIP_TRAILING_WHITESPACE) install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -m py_compile cqpid.py WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})") install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cqpid.py @@ -39,12 +42,12 @@ install(CODE "execute_process(COMMAND ${PYTHON_EXECUTABLE} -O -m py_compile cqpi install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cqpid.py ${CMAKE_CURRENT_BINARY_DIR}/cqpid.pyc ${CMAKE_CURRENT_BINARY_DIR}/cqpid.pyo - DESTINATION ${PYTHON_SITE_PACKAGES} + DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) install(FILES ${CMAKE_CURRENT_BINARY_DIR}/_cqpid_python.so RENAME _cqpid.so - DESTINATION ${PYTHON_SITE_PACKAGES} + DESTINATION ${PYTHON_SITEARCH_PACKAGES} COMPONENT ${QPID_COMPONENT_CLIENT} ) diff --git a/cpp/bindings/qpid/python/Makefile.am b/cpp/bindings/qpid/python/Makefile.am index 432fe7e764..d27cc8b3a2 100644 --- a/cpp/bindings/qpid/python/Makefile.am +++ b/cpp/bindings/qpid/python/Makefile.am @@ -19,7 +19,7 @@ if HAVE_PYTHON_DEVEL -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src/qmf -I$(top_srcdir)/src -I$(top_builddir)/src +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/bindings -I$(top_builddir)/include -I$(top_srcdir)/src/qmf -I$(top_srcdir)/src -I$(top_builddir)/src generated_file_list = \ cqpid.cpp \ @@ -29,7 +29,7 @@ EXTRA_DIST = CMakeLists.txt python.i BUILT_SOURCES = $(generated_file_list) SWIG_FLAGS = -w362,401 -$(generated_file_list): $(srcdir)/python.i $(srcdir)/../qpid.i $(srcdir)/../../swig_python_typemaps.i +$(generated_file_list): $(srcdir)/python.i $(SWIG) -c++ -python $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I$(top_srcdir)/src/qmf -I/usr/include -o cqpid.cpp $(srcdir)/python.i pylibdir = $(pyexecdir) diff --git a/cpp/bindings/qpid/python/python.i b/cpp/bindings/qpid/python/python.i index 4d8a64b376..148cad5e63 100644 --- a/cpp/bindings/qpid/python/python.i +++ b/cpp/bindings/qpid/python/python.i @@ -19,7 +19,7 @@ %module cqpid %include "std_string.i" -%include "../../swig_python_typemaps.i" +%include "qpid/swig_python_typemaps.i" /* Needed for get/setPriority methods. Surprising SWIG 1.3.40 doesn't * convert uint8_t by default. */ @@ -159,7 +159,7 @@ QPID_EXCEPTION(UnauthorizedAccess, SessionError) %rename(_setTtl) qpid::messaging::Message::setTtl; -%include "../qpid.i" +%include "qpid/qpid.i" %extend qpid::messaging::Connection { %pythoncode %{ diff --git a/cpp/bindings/qpid/qpid.i b/cpp/bindings/qpid/qpid.i deleted file mode 100644 index 352bafa3c8..0000000000 --- a/cpp/bindings/qpid/qpid.i +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%{ - -#include <qpid/messaging/exceptions.h> -#include <qpid/messaging/Address.h> -#include <qpid/messaging/Connection.h> -#include <qpid/messaging/Session.h> -#include <qpid/messaging/Receiver.h> -#include <qpid/messaging/Sender.h> -#include <qpid/messaging/Message.h> -#include <qpid/messaging/Duration.h> -#include <qpid/messaging/FailoverUpdates.h> - -// -// Wrapper functions for map-decode and list-decode. This allows us to avoid -// the complexity of output parameter mapping. -// -qpid::types::Variant::Map& decodeMap(const qpid::messaging::Message& msg) { - static qpid::types::Variant::Map map; - map.clear(); - qpid::messaging::decode(msg, map); - return map; -} - -qpid::types::Variant::List& decodeList(const qpid::messaging::Message& msg) { - static qpid::types::Variant::List list; - list.clear(); - qpid::messaging::decode(msg, list); - return list; -} - -%} - -%include <qpid/ImportExport.h> -%include <qpid/messaging/ImportExport.h> -%include <qpid/messaging/Address.h> -%include <qpid/messaging/Duration.h> -%include <qpid/messaging/Message.h> -%include <qpid/messaging/Receiver.h> -%include <qpid/messaging/Sender.h> -%include <qpid/messaging/Session.h> -%include <qpid/messaging/Connection.h> -%include <qpid/messaging/FailoverUpdates.h> - -qpid::types::Variant::Map& decodeMap(const qpid::messaging::Message&); -qpid::types::Variant::List& decodeList(const qpid::messaging::Message&); - - -%{ - -%}; - diff --git a/cpp/bindings/qpid/ruby/CMakeLists.txt b/cpp/bindings/qpid/ruby/CMakeLists.txt index 9b32ff5728..564f5655c8 100644 --- a/cpp/bindings/qpid/ruby/CMakeLists.txt +++ b/cpp/bindings/qpid/ruby/CMakeLists.txt @@ -31,7 +31,9 @@ set(GEM_OUTPUT_FILE ${GEM_OUTPUT_PATH}/pkg/qpid-${qpidc_version}.0.gem) ##------------------------------------------------------ set_source_files_properties(${CMAKE_CURRENT_SOURCE_DIR}/ruby.i PROPERTIES CPLUSPLUS ON) -include_directories(${RUBY_INCLUDE_DIRS} ${qpid-cpp_SOURCE_DIR}/include) +include_directories(${RUBY_INCLUDE_DIRS} + ${qpid-cpp_SOURCE_DIR}/include + ${qpid-cpp_SOURCE_DIR}/bindings) swig_add_module(cqpid_ruby ruby ${CMAKE_CURRENT_SOURCE_DIR}/ruby.i) swig_link_libraries(cqpid_ruby qpidmessaging qpidtypes qmf2 ${RUBY_LIBRARY}) @@ -43,7 +45,7 @@ set_source_files_properties(${swig_generated_file_fullname} PROPERTIES COMPILE_F ##---------------------------------- install(FILES ${CMAKE_CURRENT_BINARY_DIR}/libcqpid_ruby.so RENAME cqpid.so - DESTINATION ${RUBY_ARCH_DIR} + DESTINATION ${RUBY_PFX_ARCH_DIR} COMPONENT ${QPID_COMPONENT_CLIENT} ) diff --git a/cpp/bindings/qpid/ruby/ChangeLog b/cpp/bindings/qpid/ruby/ChangeLog new file mode 100644 index 0000000000..03813053d2 --- /dev/null +++ b/cpp/bindings/qpid/ruby/ChangeLog @@ -0,0 +1,4 @@ +Verison 0.22: + * Qpid::Messaging::Address can use an address string on creation. + * Qpid::Messaging::Message can use an address string for reply_to. + * Removed errors.rb and the KeyError and SessionNameException errors. diff --git a/cpp/bindings/qpid/ruby/LICENSE b/cpp/bindings/qpid/ruby/LICENSE index 232fd660d6..261eeb9e9f 100644 --- a/cpp/bindings/qpid/ruby/LICENSE +++ b/cpp/bindings/qpid/ruby/LICENSE @@ -1,7 +1,3 @@ -========================================================================= -== Apache License == -========================================================================= - Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ diff --git a/cpp/bindings/qpid/ruby/Makefile.am b/cpp/bindings/qpid/ruby/Makefile.am index a2a5dd76bd..398449c7ed 100644 --- a/cpp/bindings/qpid/ruby/Makefile.am +++ b/cpp/bindings/qpid/ruby/Makefile.am @@ -19,7 +19,7 @@ if HAVE_RUBY_DEVEL -INCLUDES = -I$(top_srcdir)/include -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src +INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/bindings -I$(top_builddir)/include -I$(top_srcdir)/src -I$(top_builddir)/src EXTRA_DIST = CMakeLists.txt ruby.i BUILT_SOURCES = cqpid.cpp @@ -27,7 +27,7 @@ SWIG_FLAGS = -w362,401 rubylibdir = $(RUBY_LIB) -cqpid.cpp: $(srcdir)/ruby.i $(srcdir)/../qpid.i $(srcdir)/../../swig_ruby_typemaps.i +cqpid.cpp: $(srcdir)/ruby.i $(SWIG) -ruby -c++ $(SWIG_FLAGS) $(INCLUDES) $(QPID_CXXFLAGS) -I/usr/include -o cqpid.cpp $(srcdir)/ruby.i rubylibarchdir = $(RUBY_LIB_ARCH) diff --git a/cpp/bindings/qpid/ruby/README.rdoc b/cpp/bindings/qpid/ruby/README.rdoc index 5c60a15588..fce87ac3e1 100644 --- a/cpp/bindings/qpid/ruby/README.rdoc +++ b/cpp/bindings/qpid/ruby/README.rdoc @@ -1,45 +1,41 @@ -= Qpid - Open Source AMQP Messaging += Qpid - Ruby language bindings for the Qpid messaging framework. -Qpid is an cross-platform enterprise messaging system. - -Version :: 0.19.0 +Qpid is a cross-platform enterprise messaging system based on the open-source +AMQP protocol. = Links Documents :: http://qpid.apache.org/ -= Installation += Building The Gemfile + +== Prerequisites -You can install Qpid with the following command. +You need to have the Qpid client libraries installed along with the related +development files (headers, etc). To install them, please see: - $ gem install qpid +http://cwiki.apache.org/qpid/developer-pages.html -== Building The Native Code +== Gemfile Creation -The Qpid gem requires that you have available the Qpid libraries and -development header files. To install them, please see: +Simply type: -http://cwiki.apache.org/qpid/developer-pages.html + $ gem build qpid_messaging.gemspec -If you are building the gem within the Qpid development environment -itself, you can specify the location of the Qpid headers and -libraries with: +This will produce a gemfile name qpid_messaging-${VERSION}.gem. -$ ruby extconfig.rb --with-qpid-lib=[path to libqpidclient.so, etc.] -$ make +== Installation -== Examples +You can install Qpid with the following command: -Take a look at the integration tests for examples on how to leverage -the messaging capabilities of Qpid in your Ruby applications. + $ gem install qpid_messaging-${VERSION}.gem == License Licensed to the Apache Software Foundation (ASF) under one or more contributor licensing agreements. -Author:: Darryl L. Pierce (mailto:dpierce@redhat.com) -Copyright:: Copyright (c) 2011, Red Hat, Inc. +Author:: Apache Qpid Project Homepage:: http://qpid.apache.org License:: Apache License 2.0 - http://www.apache.org/licenses/LICENSE-2.0.html diff --git a/cpp/bindings/qpid/ruby/Rakefile b/cpp/bindings/qpid/ruby/Rakefile deleted file mode 100644 index 99c3e13c83..0000000000 --- a/cpp/bindings/qpid/ruby/Rakefile +++ /dev/null @@ -1,137 +0,0 @@ -# Rakefile for Qpid -*- 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. -# - -task :noop - -# look for a root directory for out-of-tree builds - -OUTPUT_DIR=ENV["OUTPUT_DIR"] || "." - -require "rubygems" -require "rubygems/package_task" - -require "rake/clean" -require "rake/extensiontask" -require "rake/rdoctask" -require "rake/testtask" - -require "cucumber/rake/task" -require "spec/rake/spectask" - -CLOBBER.include("pkg") - -load "./lib/qpid/version.rb" - -#------------- -# Gem Details. -#------------- - -NAME = "qpid" -# VERSION = Qpid::VERSION -AUTHOR = "Darryl L. Pierce" -EMAIL = "dpierce@redhat.com" -HOMEPAGE = "http://qpid.apache.org" -SUMMARY = "Qpid is an enterprise messaging framework." - -desc "Default: run all tests." -task :default => :test - -desc "Runs all tests." -task :test => :"test:all" - -#--------------- -# Testing tasks. -#--------------- - -namespace :test do - - desc "Run RSpec tests." - Spec::Rake::SpecTask.new do |t| - t.ruby_opts = ['-rtest/unit'] - t.spec_files = FileList["spec/**/*_spec.rb"] - t.rcov = true - t.rcov_opts = [ - '--exclude', 'lib\/qpid.rb,spec\/,lib\/ruby', - ] - end - - desc "Run all tests (default)." - task :all => [:spec, :features] - - Cucumber::Rake::Task.new(:features) do |t| - t.libs = ["lib", "ext/nonblockio"] - t.cucumber_opts = "--format progress" - end - -end - -#--------------------- -# Documentation tasks. -#--------------------- - -Rake::RDocTask.new(:rdoc => "rdoc", - :clobber_rdoc => "rdoc:clean", - :rerdoc => "rdoc:force") do |rd| - rd.main = "README.rdoc" - rd.options << "--all" - rd.rdoc_files.include("README.rdoc", "lib/**/*.rb") -end - -#----------------- -# Package the gem. -#----------------- - -spec = Gem::Specification.new do |s| - s.name = NAME - s.version = Qpid::VERSION - s.platform = Gem::Platform::RUBY - s.extra_rdoc_files = ["README.rdoc"] - s.summary = SUMMARY - s.description = s.summary - s.author = AUTHOR - s.email = EMAIL - s.homepage = HOMEPAGE - - s.extensions = FileList["ext/**/extconf.rb"] - - s.require_path = "lib" - # DEPRECATED s.autorequire = NAME - s.files = FileList["LICENSE", - "README.rdoc", - "Rakefile", - "TODO", - "lib/**/*.rb", - "test/**/*.rb", - "examples/**/*.rb", - "ext/**/*", - "features/**/*", - "spec/**/*"] -end - -Gem::PackageTask.new(spec) do |pkg| - pkg.package_dir = "#{OUTPUT_DIR}/pkg" -end - -#------------------ -# Build native code -#------------------ - -Rake::ExtensionTask.new("cqpid", spec) - diff --git a/cpp/bindings/qpid/ruby/TODO b/cpp/bindings/qpid/ruby/TODO index 454aac9200..db2aca0195 100644 --- a/cpp/bindings/qpid/ruby/TODO +++ b/cpp/bindings/qpid/ruby/TODO @@ -1,7 +1,12 @@ -TODO Items ------------------------------------------------------------------------------ +Qpid Ruby bindigns TODO List +============================================================================== -Version 0.11.0: - * Deliver the Ruby bindings as a gem. - * Rework the blocking tasks to not bring the main thread to a halt. +Beyond this simple laundry list, you can find the list of bugs and +enhancements to be fixed by going to the Apache Qpid JIRA instance: + http://issues.apache.org/jira/browse/QPID + + +Fixes & Improvements +============================================================================== +* Fix the threading issues with blocking I/O calls (Receiver get/fetch). diff --git a/cpp/bindings/qpid/ruby/examples/client.rb b/cpp/bindings/qpid/ruby/examples/client.rb index 86ec1b7254..f400acfd13 100644 --- a/cpp/bindings/qpid/ruby/examples/client.rb +++ b/cpp/bindings/qpid/ruby/examples/client.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' if __FILE__ == $0 broker = ARGV[1] || "amqp:tcp:localhost:5672" @@ -29,9 +29,7 @@ if __FILE__ == $0 connection.open session = connection.create_session sender = session.create_sender "service_queue" - response_queue = Qpid::Messaging::Address.new("#response-queue", "", - :create => :always, - :delete => :always) + response_queue = Qpid::Messaging::Address.new("#response-queue;{create:always}") receiver = session.create_receiver response_queue ["Twas brillig, and the slithy toves", diff --git a/cpp/bindings/qpid/ruby/examples/drain.rb b/cpp/bindings/qpid/ruby/examples/drain.rb index 9e8f699e8b..8e506ea5cd 100644 --- a/cpp/bindings/qpid/ruby/examples/drain.rb +++ b/cpp/bindings/qpid/ruby/examples/drain.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' require 'optparse' options = { diff --git a/cpp/bindings/qpid/ruby/examples/hello_world.rb b/cpp/bindings/qpid/ruby/examples/hello_world.rb index c014fb8bd5..1f4954dde9 100644 --- a/cpp/bindings/qpid/ruby/examples/hello_world.rb +++ b/cpp/bindings/qpid/ruby/examples/hello_world.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' # This is your classic Hello World application, written in # Ruby, that uses Qpid. It demonstrates how to send and diff --git a/cpp/bindings/qpid/ruby/examples/map_receiver.rb b/cpp/bindings/qpid/ruby/examples/map_receiver.rb index e08bd295ba..16704dd48e 100644 --- a/cpp/bindings/qpid/ruby/examples/map_receiver.rb +++ b/cpp/bindings/qpid/ruby/examples/map_receiver.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' broker = ARGV[0] || "amqp:tcp:127.0.0.1:5672" address = ARGV[1] || "message_queue; {create: always}" diff --git a/cpp/bindings/qpid/ruby/examples/map_sender.rb b/cpp/bindings/qpid/ruby/examples/map_sender.rb index 3fb7ca58e3..1908774c31 100644 --- a/cpp/bindings/qpid/ruby/examples/map_sender.rb +++ b/cpp/bindings/qpid/ruby/examples/map_sender.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' broker = ARGV[0] || "amqp:tcp:127.0.0.1:5672" address = ARGV[1] || "message_queue; {create: always}" diff --git a/cpp/bindings/qpid/ruby/examples/server.rb b/cpp/bindings/qpid/ruby/examples/server.rb index 0cc0e30216..a589bea799 100644 --- a/cpp/bindings/qpid/ruby/examples/server.rb +++ b/cpp/bindings/qpid/ruby/examples/server.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' if __FILE__ == $0 broker = ARGV[0] || "amqp:tcp:localhost:5672" diff --git a/cpp/bindings/qpid/ruby/examples/spout.rb b/cpp/bindings/qpid/ruby/examples/spout.rb index ecc47fb15a..71c04d8709 100644 --- a/cpp/bindings/qpid/ruby/examples/spout.rb +++ b/cpp/bindings/qpid/ruby/examples/spout.rb @@ -19,7 +19,7 @@ $:.unshift File.join(File.dirname(__FILE__), "..", "lib") -require 'qpid' +require 'qpid_messaging' require 'optparse' options = { diff --git a/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb b/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb index 90292d4bec..fc9e65d562 100644 --- a/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb +++ b/cpp/bindings/qpid/ruby/ext/cqpid/extconf.rb @@ -26,9 +26,10 @@ require 'mkmf' # Setup the build environment. -$CFLAGS = "-fPIC -fno-inline -x c++" +$CFLAGS = "-fPIC -fno-inline -x c++ -lstdc++" REQUIRED_LIBRARIES = [ + 'stdc++', 'qpidclient', 'qpidcommon', 'qpidmessaging', diff --git a/cpp/bindings/qpid/ruby/features/creating_a_receiver.feature b/cpp/bindings/qpid/ruby/features/creating_a_receiver.feature index 1f758153af..def686f881 100644 --- a/cpp/bindings/qpid/ruby/features/creating_a_receiver.feature +++ b/cpp/bindings/qpid/ruby/features/creating_a_receiver.feature @@ -25,5 +25,5 @@ Feature: Creating a receiver Scenario: Using an Address object Given an open session - And an Address with the name "create-receiver-test" and subject "foo" and option "create" set to "always" and "delete" set to "always" + And an Address with the string "create-receiver-test;{create:always}" Then creating a receiver with an Address succeeds diff --git a/cpp/bindings/qpid/ruby/features/creating_a_sender.feature b/cpp/bindings/qpid/ruby/features/creating_a_sender.feature index 1c09ff837d..c12b10e054 100644 --- a/cpp/bindings/qpid/ruby/features/creating_a_sender.feature +++ b/cpp/bindings/qpid/ruby/features/creating_a_sender.feature @@ -21,5 +21,5 @@ Feature: Creating a sender Scenario: Using an Address object Given an open session - And an Address with the name "my-queue" and subject "my-subject" and option "create" set to "always" + And an Address with the string "my-queue/my-subject;{create:always}" Then creating a sender with an Address succeeds diff --git a/cpp/bindings/qpid/ruby/features/step_definitions/address_steps.rb b/cpp/bindings/qpid/ruby/features/step_definitions/address_steps.rb index 0531e5ee69..a7eca6f9ce 100644 --- a/cpp/bindings/qpid/ruby/features/step_definitions/address_steps.rb +++ b/cpp/bindings/qpid/ruby/features/step_definitions/address_steps.rb @@ -17,15 +17,6 @@ # under the License. # -Given /^an Address with the name "([^"]*)" and subject "([^"]*)" and option "([^"]*)" set to "([^"]*)"$/ do |name, subject, key, value| - options = Hash.new - options["#{key}"] = "#{value}" - @address = Qpid::Messaging::Address.new "#{name}", "#{subject}", options -end - -Given /^an Address with the name "([^"]*)" and subject "([^"]*)" and option "([^"]*)" set to "([^"]*)" and "([^"]*)" set to "([^"]*)"$/ do |name, subject, key1, value1, key2, value2| - options = Hash.new - options["#{key1}"] = "#{value1}" - options["#{key2}"] = "#{value2}" - @address = Qpid::Messaging::Address.new "#{name}", "#{subject}", options +Given /^an Address with the string "(.*?)"$/ do |address| + @address = Qpid::Messaging::Address.new "#{address}" end diff --git a/cpp/bindings/qpid/ruby/features/support/env.rb b/cpp/bindings/qpid/ruby/features/support/env.rb index 1d15f56fc9..cc0097ca8b 100644 --- a/cpp/bindings/qpid/ruby/features/support/env.rb +++ b/cpp/bindings/qpid/ruby/features/support/env.rb @@ -19,4 +19,4 @@ $LOAD_PATH.unshift(File.dirname(__FILE__) + "/../../lib") -require 'qpid' +require 'qpid_messaging' diff --git a/cpp/bindings/qpid/ruby/lib/qpid.rb b/cpp/bindings/qpid/ruby/lib/qpid.rb deleted file mode 100644 index 1f00c136c1..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid.rb +++ /dev/null @@ -1,29 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'qpid/errors' -require 'qpid/duration' -require 'qpid/address' -require 'qpid/encoding' -require 'qpid/message' -require 'qpid/sender' -require 'qpid/receiver' -require 'qpid/session' -require 'qpid/connection' - diff --git a/cpp/bindings/qpid/ruby/lib/qpid/connection.rb b/cpp/bindings/qpid/ruby/lib/qpid/connection.rb deleted file mode 100644 index 12669bc947..0000000000 --- a/cpp/bindings/qpid/ruby/lib/qpid/connection.rb +++ /dev/null @@ -1,162 +0,0 @@ -# -# Licensed to the Apache Software Foundation (ASF) under one -# or more contributor license agreements. See the NOTICE file -# distributed with this work for additional information -# regarding copyright ownership. The ASF licenses this file -# to you under the Apache License, Version 2.0 (the -# "License"); you may not use this file except in compliance -# with the License. You may obtain a copy of the License at -# -# http://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, -# software distributed under the License is distributed on an -# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY -# KIND, either express or implied. See the License for the -# specific language governing permissions and limitations -# under the License. -# - -require 'cqpid' - -module Qpid - - module Messaging - - # Establishes a connection to a remote endpoint. - class Connection - - attr_reader :options # :nodoc: - - # Creates a connection object, but does not actually connect to - # the specified location. - # - # ==== Options - # - # :url - the URL for the broker (def. +"localhost"+) - # :options - connection options (def. +{}+) - # - # ==== Controlling Reconnect Behavior - # - # The following connection options can be used to configure - # the reconnection behavior for this connection. - # - # * :username - # * :password - # * :heartbeat - # * :tcp_nodelay - # * :sasl_mechanism - # * :sasl_service - # * :sasl_min_ssf - # * :sasl_max_ssf - # * :transport - # * :reconnect - +true+ or +false+; indicates wehtehr to attempt reconnections - # * :reconnect_timeout - the number of seconds to attempt reconnecting - # * :reconnect_limit - the number of retries before reporting failure - # * :reconnect_interval_min - initial delay, in seconds, before attempting a reconnection - # * :reconnect_interval_max - number of seconds to wait before additional reconnect attempts - # * :reconnect_interval - shorthand for setting both min and max values - # * :reconnect_urls - a list of alternate URLs to use for reconnection attempts - # - # ==== Examples - # - # conn = Qpid::Messaging::Connnection.new - # conn = Qpid::Messaging::Connection.new :url => "amqp:tcp:broker1.domain.com:5672" - # conn = Qpid::Messaging::Connection.new :options => {:username => "login", :password => "password"} - # - def initialize(opts = {}) - @url = opts[:url] || "localhost" - @options = convert_options(opts[:options] || {}) - @connection_impl = opts[:impl] || Cqpid::Connection.new(@url, @options) - end - - def connection_impl # :nodoc: - @connection_impl - end - - # Establishes the connection. - # - # ==== Examples - # - # conn.open unless conn.open? - # - def open - @connection_impl.open - end - - # Reports whether the connection is open. - # - # ==== Examples - # - # conn.close if conn.open? - # - def open?; true && !@connection_impl.nil? && @connection_impl.isOpen; end - - # Closes the connection. - def close; @connection_impl.close; end - - # Creates a new session. - # - # ==== Arguments - # - # * :name - specifies the name for this session - # * :transactional - if +true+ then a creates a transaction session (def. +false+) - # - # ==== Examples - # - # session = conn.create_session :name => "session1" - # session = conn.create_session :transaction => true - # - def create_session(args = {}) - name = args[:name] || "" - if open? - if args[:transactional] - session = @connection_impl.createTransactionalSession name - else - session = @connection_impl.createSession name - end - return Session.new(self, session) - else - raise RuntimeError.new "No connection available." - end - end - - # Returns a session for the specified session name. - # - # ==== Examples - # - # begin - # session = conn.session "mysession" - # rescue SessionNameException => error - # puts "No such session." - # end - # - def session name - begin - session_impl = @connection_impl.getSession name - Qpid::Messaging::Session.new self, session_impl if session_impl - rescue - raise Qpid::Messaging::SessionNameException.new "No such session: #{name}" - end - end - - # Returns the username used to authenticate with the connection. - def authenticated_username; @connection_impl.getAuthenticatedUsername if open?; end - - private - - def convert_options(options) - result = {} - unless options.nil? || options.empty? - options.each_pair {|key, value| result[key.to_s] = value.to_s} - end - - return result - end - - end - - end - -end - diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging.rb new file mode 100644 index 0000000000..2b5348f298 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging.rb @@ -0,0 +1,82 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 'cqpid' +require 'qpid_messaging/duration' +require 'qpid_messaging/address' +require 'qpid_messaging/encoding' +require 'qpid_messaging/message' +require 'qpid_messaging/sender' +require 'qpid_messaging/receiver' +require 'qpid_messaging/session' +require 'qpid_messaging/connection' + +module Qpid + + # The Qpid Messaging framework is an enterprise messaging framework + # based on the open-source AMQP protocol. + # + # ==== Example Application + # + # Here is a simple example application. It creates a link to a broker located + # on a system named *broker.myqpiddomain.com*. It then creates a new messaging + # queue named "qpid-examples" and publishes a message to it. It then consumes + # that same message and closes the connection. + # + # require 'rubygems' + # gem 'qpid_messaging' + # require 'qpid_messaging' + # + # # create a connection, open it and then create a session named "session1" + # conn = Qpid::Messaging::Connection.new :name => "broker.myqpiddomain.com" + # conn.open + # session = conn.create_session "session1" + # + # # create a sender and a receiver + # # the sender marks the queue as one that is deleted when trhe sender disconnects + # send = session.create_sender "qpid-examples;{create:always,delete:always}" + # recv = session.create_receiver "qpid-examples" + # + # # create an outgoing message and send it + # outgoing = Qpid::Messaging::Message.new :content => "The time is #{Time.new}" + # sender.send outgoing + # + # # set the receiver's capacity to 10 and then check out many messages are pending + # recv.capacity = 10 + # puts "There are #{recv.available} messages waiting." # should report 1 message + # + # # get the nextwaiting message, which should be in the local queue now, + # # and output the contents + # incoming = recv.get Qpid::Messaging::Duration::IMMEDIATE + # puts "Received the following message: #{incoming.content}" + # # the output should be the text that was sent earlier + # + # # acknowledge the message, letting the sender know the message was received + # puts "The sender currently has #{send.unsettled} message(s) pending." + # # should report 1 unsettled message + # session.acknowledge incoming # acknowledge the received message + # puts "Now sender currently has #{send.unsettled} message(s) pending." + # # should report 0 unsettled messages + # + # # close the connection + # conn.close + # + module Messaging; end + +end diff --git a/cpp/bindings/qpid/ruby/lib/qpid/address.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/address.rb index 266d8668d6..0879f0fcd1 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/address.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/address.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,9 +15,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -require 'cqpid' +#++ module Qpid @@ -26,13 +24,17 @@ module Qpid # Address represents an address to which messages can be sent or from # which they can be received. # - # An Address can be described using the following pattern: + # == The +Address+ String + # + # An +Address+ can be described using the following pattern: # # <address> [ / <subject> ] ; [ { <key> : <value> , ... } ] # # where *address* is a simple name and *subject* is a subject or subject # pattern. # + # === Options + # # The options, enclosed in curly braces, are key:value pairs delimited by # a comma. The values can be nested maps also enclosed in curly braces. # Or they can be lists of values, where they are contained within square @@ -42,56 +44,49 @@ module Qpid # # The following are the list of supported options: # - # [:create] + # [create] # Indicates if the address should be created; values are *always*, # *never*, *sender* or *reciever*. # - # [:assert] + # [assert] # Indicates whether or not to assert any specified node properties; # values are *always*, *never*, *sender* or *receiver*. # - # [:delete] + # [delete] # Indicates whether or not to delete the addressed node when a sender # or receiver is cancelled; values are *always*, *never*, *sender* or # *receiver*. # - # [:node] + # [node] # A nested map describing properties for the addressed node. Properties # are *type* (*topic* or *queue*), *durable* (a boolean), *x-declare* - # (a nested map of amqp 0.10-specific options) and *x-bindings*. (nested - # list which specifies a queue, exchange or a binding key and arguments. + # (a nested map of amqp 0.10-specific options) and *x-bindings* (nested + # list which specifies a queue, exchange or a binding key and arguments). # - # [:link] + # [link] # A nested map through which properties of the link can be specified; # properties are *durable*, *reliability*, *x-declare*, *x-subscribe* # and *x-bindings*. # - # [:mode] + # [mode] # (*For receivers only*) indicates whether the receiver should consume # or browse messages; values are *consume* (the default) and *browse*. - # class Address - # Creates a new +Address+ object. + # Creates a new +Address+ from an address string. # - # ==== Options + # ==== Attributes # - # * name - The name for the +Address+. - # * subject - The subject for the +Address+ - # * :create - See the class documentation. - # * :assert - See the class documentation. - # * :delete - See the class documentation. - # * :node - See the class documentation. - # * :link - See the class documentation. - # * :mode - See the class documentation. + # * +address+ - the address string # # ==== Examples # - # addr = Qpid::Messaging::Address.new "my-queue" - # addr = Qpid::Messaging::Address.new "my-queue", "testing", :create => :always + # # create a new address for a queue named "my-queue" that will + # # be created if it doesn't already exist + # addr = Qpid::Messaging::Address.new "my-queue;{create:always}" # - def initialize(name, subject, options = {}, _type = "", address_impl = nil) - @address_impl = address_impl || Cqpid::Address.new(name, subject, convert_options(options), _type) + def initialize(address, address_impl = nil) + @address_impl = address_impl || Cqpid::Address.new(address) end def address_impl # :nodoc: @@ -102,7 +97,10 @@ module Qpid # # ==== Examples # - # puts "The address name is #{addr.name}." + # # display the name of the address + # addr = Qpid::Messaging::Address.new "foo;{create:always}" + # # outputs the word 'foo' + # puts addr.name # def name; @address_impl.getName; end @@ -110,6 +108,9 @@ module Qpid # # ==== Examples # + # # create a new address with the name "my-queue" + # addr = Qpid::Messaging::Address.new "my-queue/my-subject;{create:always}" + # # changes the name to "my-new-queue" # addr.name = "my-new-queue" # def name=(name); @address_impl.setName name; end @@ -118,7 +119,8 @@ module Qpid # # ==== Examples # - # puts "The subject is #{addr.subject}." + # # creates a new address with the subject "bar" + # addr = Qpid::Messaging::Address.new "my-queue/bar;{create:always}" # def subject; @address_impl.getSubject; end @@ -126,30 +128,40 @@ module Qpid # # ==== Examples # - # addr.subject = "testing" + # # creates an address with the subject "example" + # addr = Qpid::Messaging::Address.new "my-queue/example;{create:always}" + # # changes the subject to "test" + # addr.subject = "test" # def subject=(subject); @address_impl.setSubject(subject); end # Returns the type for the +Address+. - # - # ==== Examples - # - # puts "The address is a #{address.address_type}." - # - #--- + #-- # We cannot use "type" since that clashes with the Ruby object.type # identifier. + #++ def address_type; @address_impl.getType; end # Sets the type for the +Address+. # # The type of the address determines how +Sender+ and +Receiver+ objects - # are constructed for it. If no type is specified then it will be - # determined by querying the broker. + # are constructed for it. It also affects how a reply-to address is + # encoded. + # + # If no type is specified then it will be determined by querying the + # broker. Explicitly setting the type prevents this. + # + # Values are either *queue* or *topic*. # - # ===== Options + # ==== Options + # + # * +type+ - the address type + # + # ==== Examples # - # * type - the address type + # # creates an queue address + # addr = Qpid::Messaging::Address.new "my-queue;{create:always}" + # addr.address_type = "queue" # def address_type=(type); @address_impl.setType(type); end @@ -163,6 +175,7 @@ module Qpid # ==== Examples # # addr.options = :create => :always + # addr.options = :create => :always, :delete => :always # def options=(options = {}); @address_impl.setOptions(convert_options(options)); end diff --git a/cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb new file mode 100644 index 0000000000..6d637a1665 --- /dev/null +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/connection.rb @@ -0,0 +1,189 @@ +#-- +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT 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 Qpid + + module Messaging + + # A +Connection+ represents a network connection to a remote endpoint. + class Connection + + attr_reader :options # :nodoc: + + # Creates a connection object. Raises a MessagingError if an invalid + # connection option is used. + # + # == Options + # + # * +:url+ - the URL for the broker + # * +:options+ - connection options + # + # == Controlling Reconnect Behavior + # + # The following connection options can be used to configure + # the reconnection behavior for this connection. + # + # * +:username+ - the authentication username + # * +:password+ - the authentication password + # * +:heartbeat+ + # * +:tcp_nodelay+ + # * +:sasl_mechanism+ + # * +:sasl_service+ + # * +:sasl_min_ssf+ + # * +:sasl_max_ssf+ + # * +:transport+ + # * +:reconnect+ - indicates whether to attempt reconnections + # * +:reconnect_timeout+ - the number of seconds to attempt reconnecting + # * +:reconnect_limit+ - the number of retries before reporting failure + # * +:reconnect_interval_min+ - initial delay, in seconds, before attempting a reconnection + # * +:reconnect_interval_max+ - number of seconds to wait before additional reconnect attempts + # * +:reconnect_interval+ - shorthand for setting both min and max values + # * +:reconnect_urls+ - a list of alternate URLs to use for reconnection attempts + # + # == Examples + # + # # creates a connection to the broker running local *localhost* + # conn = Qpid::Messaging::Connnection.new + # # creates a connection to *broker1.domain.com* on port *5672* + # conn = Qpid::Messaging::Connection.new :url => "amqp:tcp:broker1.domain.com:5672" + # # creates a connection to localhost with the specified authentication credentials + # conn = Qpid::Messaging::Connection.new :options => {:username => "login", :password => "password"} + # + def initialize(opts = {}) + @url = opts[:url] || "localhost" + @options = Qpid::Messaging.stringify(opts[:options] || {}) + @connection_impl = opts[:impl] || Cqpid::Connection.new(@url, @options) + end + + def connection_impl # :nodoc: + @connection_impl + end + + # Establishes the connection. + # + # == Examples + # + # # open a connection if it's not already open + # conn.open unless conn.open? + # + def open + @connection_impl.open + end + + # Reports whether the connection is open. + # + # == Examples + # + # # close the connection if it's not already closed + # conn.close if conn.open? + # + def open?; true && !@connection_impl.nil? && @connection_impl.isOpen; end + + # Closes the connection. + # + # == Examples + # + # # close a connection + # conn.close + # + def close; @connection_impl.close; end + + # Creates a new session. + # + # == Arguments + # + # * +:name+ - specifies the name for this session + # * +:transactional+ - if +true+ then a creates a transaction session (def. +false+) + # + # == Examples + # + # # create a session named 'session1' + # session = conn.create_session :name => "session1" + # # create a transactional session + # session = conn.create_session :transaction => true + # + def create_session(args = {}) + name = args[:name] || "" + if open? + if args[:transactional] + session = @connection_impl.createTransactionalSession name + else + session = @connection_impl.createSession name + end + return Session.new(self, session) + else + raise RuntimeError.new "No connection available." + end + end + + # Returns a Session with the given name. Raises an exception if no + # session with the given name exists. + # + # == Options + # + # * +name+ - the existing session's name + # + # == Examples + # + # # retrieve a session named 'mysession' from the current connection + # name = "my-session" + # # if no such session exists then catchh the exception raised + # begin + # session = conn.session name + # rescue MessagingException => error + # puts "No such session: #{name}." + # end + # + def session name + session_impl = @connection_impl.getSession name + Qpid::Messaging::Session.new self, session_impl if session_impl + end + + # Returns the username used to authenticate with the connection. + # + # If the connection did not user authentication credentials, then the + # username returned is "anonymous". + # + # == Examples + # + # # create a new connection for user "qpiduser" + # conn = Qpid::Messaging::Connection.new :username => "qpiduser" + # conn.open + # # displays the authenticate username + # puts "Connected as #{conn.authenticated_username}" # should say 'qpiduser' + # + def authenticated_username; @connection_impl.getAuthenticatedUsername if open?; end + + private + + def convert_options(options) + result = {} + unless options.nil? || options.empty? + options.each_pair {|key, value| result[key.to_s] = value.to_s} + end + + return result + end + + end + + end + +end + diff --git a/cpp/bindings/qpid/ruby/lib/qpid/duration.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/duration.rb index e1ddd79cb6..11c903dade 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/duration.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/duration.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,9 +15,7 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -require 'cqpid' +#++ module Qpid @@ -25,19 +23,21 @@ module Qpid # A Duration represents a period of time in milliseconds # - # It defines the following named values as symbols: + # == Named Durations # - # [:FOREVER] + # The following named +Durations+ are available as symbols: + # + # [FOREVER] # The maximum integer value for the platform. Effectively this will wait # forever. # - # [:IMMEDIATE] + # [IMMEDIATE] # An alias for 0 milliseconds. # - # [:SECOND] + # [SECOND] # An alias for 1,000 milliseconds. # - # [:MINUTE] + # [MINUTE] # And alias for 60,000 millisecons. # class Duration @@ -46,12 +46,13 @@ module Qpid # # ==== Options # - # * length - The duration in milliseconds. + # * +length+ - The duration in +milliseconds+. # # ==== Examples # - # # Wait up to 10 seconds for an incoming message - # receiver.get Qpid::Messaging::Duration.new 10000 + # # creates a duration of 15 seconds + # # REMEMBER: Duration deals in milliseconds + # delay = Qpid::Messaging::Duration.new 15000 # def initialize length @duration_impl = Cqpid::Duration.new length @@ -61,18 +62,50 @@ module Qpid @duration_impl end - # Returns the period of time in milliseconds + # Returns the period of time in +milliseconds+. # # ==== Examples # - # duration = Qpid::Messaging::Duration.new :length => 5000 - # puts "Waiting #{duration.milliseconds} ms for a message." - # msg = receiver.fetch duration + # # doubling growth in waiting for messages in a loop + # do loop + # set the base duration waiting length + # timeout = Qpid::Messaging::Duration::SECOND + # msg = nil + # # loop until we receive a message + # while msg.nil? + # puts "Waiting #{timeout.milliseconds}ms" + # msg = recv.get timeout + # # if nothing was received, double the duration + # if msg.nil? + # # double out timeout + # timeout = timeout * 2 + # else + # # do something with the message + # puts "Received: #{msg.content}" + # end + # end + # end # def milliseconds @duration_impl.getMilliseconds end + # Multiplies the duration of the +Duration+ and returns a new instance. + # + # Raises exceptions on a negative factor. Returns + # Qpid::Messaging::Duration::IMMEDIATE when the factor is 0. + # + # ==== Examples + # + # # return a duration that is 2 minutes (120,000 ms) + # twominutes = Qpid::Messaging::Duration::MINUTE * 2 + # + def *(factor) + raise TypeError.new "Factors must be non-zero positive values" if factor < 0 + return Qpid::Messaging::Duration::IMMEDIATE if factor.zero? + Qpid::Messaging::Duration.new((self.milliseconds * factor).floor) + end + def self.add_item(key, value) # :nodoc: @hash ||= {} @hash[key] = Duration.new value diff --git a/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/encoding.rb index 2f20fab18e..ac0fbc32a7 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/encoding.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/encoding.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,45 +15,60 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -require 'cqpid' +#++ module Qpid module Messaging # Encodes the supplied content into the given message. - def self.encode content, message, encoding = nil - prepared = content - case content - when Hash - prepared = {} - content.each_pair do |key,value| - prepared[key.to_s] = value.to_s - end - Cqpid::encode prepared, message.message_impl - when Array - prepared = [] - content.each {|value| prepared << value.to_s} - Cqpid::encode prepared, message.message_impl - end + def self.encode content, message, encoding = nil # :nodoc: + Cqpid::encode content, message.message_impl, encoding end # Decodes and returns the message's content. - def self.decode(message, content_type = nil) - content_type = message.content_type unless content_type + def self.decode(message, content_type = nil) # :nodoc: + content_type = message.content_type if content_type.nil? case content_type when "amqp/map" - Cqpid.decodeMap message.message_impl + return Cqpid.decodeMap message.message_impl when "amqp/list" - Cqpid.decodeList message.message_impl + return Cqpid.decodeList message.message_impl end message.content end + # Takes as input any type and converts anything that's a symbol + # into a string. + def self.stringify(value) # :nodoc: + # set the default value + result = value + + case value + + when Symbol + result = value.to_s + + when Hash + result = {} + value.each_pair do |key, value| + result[stringify(key)] = stringify(value) + end + + when Array + result = [] + value.each do |element| + result << stringify(element) + end + + end + + return result + + end + end end diff --git a/cpp/bindings/qpid/ruby/lib/qpid/message.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/message.rb index edef0ac2a0..e167800455 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/message.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/message.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,29 +15,26 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -require 'cqpid' +#++ module Qpid module Messaging # A +Message+ represents an routable piece of information. - # - # The content for a message is automatically encoded and decoded. - # class Message - # Creates a new instance of +Message+. + # Creates a +Message+. # # ==== Options # - # * :content - The content. + # * +:content+ - the content # # ==== Examples # + # # create a simple message and sends it # message = Qpid::Messaging::Message.new :content => "This is a message." + # sender.send message # def initialize(args = {}) @message_impl = (args[:impl] if args[:impl]) || nil @@ -51,54 +48,48 @@ module Qpid @message_impl end - # Sets the address to which replies should be sent for the +Message+. + # Sets the reply-to address. # - # *NOTE:* The address must be an instance of Address. + # The address can either be an instance of Address or else and + # address string. # # ==== Options # - # * address - an instance of +Address+ + # * +address+ - the address # # ==== Examples # + # # set replies using an Address # msg.reply_to = Qpid:Messaging::Address.new "my-responses" + # # set replies using an address string + # msg.reply_to = "my-feed/responses" # def reply_to=(address) - raise ArgumentError, "Agument must be an Address" unless address.is_a? Qpid::Messaging::Address + address = Qpid::Messaging::Address.new "#{address}" if !address.is_a? Qpid::Messaging::Address + @message_impl.setReplyTo address.address_impl end # Returns the reply to address for the +Message+. - # def reply_to address_impl = @message_impl.getReplyTo # only return an address if a reply to was specified - Qpid::Messaging::Address.new(nil, nil, nil, nil, address_impl) if address_impl + Qpid::Messaging::Address.new(nil, address_impl) if address_impl end # Sets the subject for the +Message+. # # ==== Options # - # * subject - the subject - # - # ==== Examples - # - # msg.subject = "mysubject" - # + # * +subject+ - the subject def subject=(subject); @message_impl.setSubject subject; end # Returns the subject of the +Message+. - # - # ==== Options - # - # puts "The subject is #{msg.subject}" - # def subject; @message_impl.getSubject; end # Sets the content type for the +Message+. # - # This should be set by the sending applicaton and indicates to + # This should be set by the sending application and indicates to the # recipients of the message how to interpret or decode the content. # # By default, only dictionaries and maps are automatically given a content @@ -107,23 +98,17 @@ module Qpid # # ==== Options # - # * content_type - the content type. - # - def content_type=(content_type); @message_impl.setContentType content_type; end - - # Returns the content type for the +Message+. + # * +content_type+ - the content type # # ==== Examples # - # case msg.content_type - # when "myapp/image" - # ctl.handle_image msg - # end - # when "myapp/audio" - # ctl.handle_audio msg - # end - # end + # # send base64 encoded data in a mesage + # msg = Qpid::Messaging::Message.new :content = "UXBpZCBSdWxlcyEK" + # msg.content_type = "application/base64" # + def content_type=(content_type); @message_impl.setContentType content_type; end + + # Returns the content type for the +Message+. def content_type; @message_impl.getContentType; end # Sets the message id. @@ -133,16 +118,17 @@ module Qpid # # ==== Options # - # * id - the id + # * +id+ - the id # # ==== Examples # + # # this example only works in Ruby >= 1.9, for 1.8 use a UUID library + # require 'SecureRandom' + # msg.message_id = SecureRandom.uuid # def message_id=(message_id); @message_impl.setMessageId message_id.to_s; end # Returns the message id. - # - # See +message_id=+ for details. def message_id; @message_impl.getMessageId; end # Sets the user id for the +Message+. @@ -151,44 +137,38 @@ module Qpid # the connection itself, as the messaging infrastructure will verify # this. # - # See +Qpid::Messaging::Connection.authenticated_username+ + # See Qpid::Messaging::Connection.authenticated_username # # *NOTE:* If the id is not a +String+ then the id is set using # the object's string representation. # # ==== Options # - # * id - the id + # * +id+ - the id # def user_id=(user_id); @message_impl.setUserId user_id; end # Returns the user id for the +Message+. - # - # See +user_id=+ for details. - # def user_id; @message_impl.getUserId; end # Sets the correlation id of the +Message+. # # The correlation id can be used as part of a protocol for message - # exchange patterns; e.g., a requestion-response pattern might require + # exchange patterns; e.g., a request-response pattern might require # the correlation id of the request and the response to match, or it # might use the message id of the request as the correlation id on - # the response + # the response. # # *NOTE:* If the id is not a +String+ then the id is setup using # the object's string representation. # # ==== Options # - # * id - the id + # * +id+ - the id # def correlation_id=(correlation_id); @message_impl.setCorrelationId correlation_id; end # Returns the correlation id of the +Message+. - # - # *NOTE:* See +correlation_id=+ for details. - # def correlation_id; @message_impl.getCorrelationId; end # Sets the priority of the +Message+. @@ -202,19 +182,21 @@ module Qpid # # ==== Options # - # * priority - the priority + # * +priority+ - the priority # def priority=(priority); @message_impl.setPriority priority; end # Returns the priority for the +Message+. - # def priority; @message_impl.getPriority; end # Sets the time-to-live in milliseconds. # + # This can be used by the messaging infrastructure to discard messages + # that are no longer of relevance. + # # ==== Options # - # * duration - the number of milliseconds + # * +duration+ - the number of milliseconds # def ttl=(duration) if duration.is_a? Qpid::Messaging::Duration @@ -231,16 +213,15 @@ module Qpid # # This is a hint to the messaging infrastructure that the message # should be persisted or otherwise stored. This helps to ensure - # that th emessage is not lost during to failures or a shutdown. + # that the message is not lost due to failures or a shutdown. # # ==== Options # - # * durable - the durability flag (def. false) + # * +durable+ - the durability flag (def. false) # def durable=(durable); @message_impl.setDurable durable; end # Returns the durability for the +Message+. - # def durable; @message_impl.getDurable; end # This is a hint to the messaging infrastructure that if de-duplication @@ -249,17 +230,16 @@ module Qpid # # ==== Options # - # * redelivered - sets the redelivered state (def. false) + # * +redelivered+ - sets the redelivered state (def. false) # # ==== Examples # - # # processed is an array of processed message ids + # # processed is a collection of messages already received # msg.redelivered = true if processed.include? msg.message_id # def redelivered=(redelivered); @message_impl.setRedelivered redelivered; end # Returns whether the +Message+ has been marked as redelivered. - # def redelivered; @message_impl.getRedelivered; end # Returns all named properties. @@ -267,14 +247,13 @@ module Qpid # *NOTE:* It is recommended to use the []= method for # retrieving and setting properties. Using this method may # result in non-deterministic behavior. - # def properties; @message_impl.getProperties; end # Returns the value for the named property. # # ==== Options # - # * name - the property name + # * +name+ - the property name # # ==== Examples # @@ -285,44 +264,51 @@ module Qpid # Assigns a value to the named property. # - # *NOTE:* Both the key or the value may be a symbol, but they will - # both be converted to a +String+ for ease of transport. + # A property's name or value, if a symbol, will be converted to a string + # representation. However, you will still be able to access them using + # a symbol for the name. # # ==== Options # - # * name - the property name - # * value - the property value - def []=(key, value); @message_impl.setProperty(key.to_s, value.to_s); end + # * +name+ - the property name + # * +value+ - the property value + # + # ==== Examples + # + # # set the signed attribute on a message and then retrieve it + # msg[:signed] = true # sets "signed" => true + # puts "It's signed" if msg["signed"] # outputs "It's signed" + # + def []=(key, value) + @message_impl.setProperty(key.to_s, + Qpid::Messaging.stringify(value)) + end # Sets the content for the +Message+. # # Content is automatically encoded for Array and Hash types. Other types - # need to set their own content types (via +content_type+) in order to + # need to set their own content types (via content_type) in order to # specify how recipients should process the content. # # ==== Options # - # * content - the content + # * +content+ - the content # # ==== Examples # - # msg.content = "This is a simple message." # a simple message - # msg.content = {:foo => :bar} # content is automatically encoded + # # set a simple content for a message + # msg.content = "This is a simple message." + # # sets content that is automatically encoded + # msg.content = {:foo => :bar} # def content=(content) content_type = nil - @content = content + @content = Qpid::Messaging.stringify(content) case @content when Hash content_type = "amqp/map" - new_content = {} - content.each_pair{|key, value| new_content[key.to_s] = value.to_s} - @content = new_content when Array - new_content = [] content_type = "amqp/list" - content.each {|element| new_content << element.to_s} - @content = new_content end if content_type.nil? @message_impl.setContent @content @@ -356,8 +342,7 @@ module Qpid @content end - # Returns the content's size. - # + # Returns the content's size in bytes. def content_size; @message_impl.getContentSize; end end diff --git a/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/receiver.rb index 0ce16309ed..05ee925212 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/receiver.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/receiver.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,27 +15,32 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -require 'cqpid' - -require 'qpid/duration' +#++ module Qpid module Messaging - # Receiver is the entity through which messages are received. + # +Receiver+ is the entity through which messages are received. # - # An instance of Receiver can only be created using an active (not - # previously closed) Session. + # An instance of +Receiver+ can only be created using an active (i.e., not + # previously closed) Session. See Qpid::Messaging::Session.create_receiver + # for more details. # # ==== Example # + # # create a connection and a session # conn = Qpid::Messaging::Connection.new :url => "mybroker:5762" # conn.open # session = conn.create_session - # receiver = session.create_receiver "my-sender-queue" + # + # # create a receiver that listens on the "updates" topic of "alerts" + # receiver = session.create_receiver "alerts/updates" + # + # # wait for an incoming message and process it + # incoming = receiver.get Qpid::Messaging::Duration::FOREVER + # process(incoming) + # class Receiver def initialize(session, receiver_impl) # :nodoc: @@ -50,27 +55,24 @@ module Qpid # Retrieves a message from the local queue, or waits for up to # the duration specified for one to become available. # - # If a block is given, then it will be invaked after the next message - # is received or the call times out, passing in the message or nil - # respectively. + # If no message is received within the specified time then a + # MessagingException is raised. # # ==== Options - # * duration - the timeout to wait (def. Duration::FOREVER) - # - # ==== Examples # - # msg = rcvr.get # Uses the default timeout of forever + # * duration - the timeout to wait # - # msg = rcvr.get Qpid::Messaging::Duration::IMMEDIATE # returns a message or exits immediately + # ==== Examples # - # # passes in a block to handle the received message - # rcvr.get Qpid::Messaging::Duration::SECOND do |message| - # if message.nil? - # puts "No message was received." - # else - # puts "Received this message: #{message.content}" - # end + # # retrieves a message, also handles exceptions raised on no messages + # begin + # # checks for a message, returning immediately + # msg = recv.get Qpid::Messaging::Duration::IMMEDIATE + # puts "Received this message: #{message.content}" + # rescue + # puts "No messages available. # end + # def get(duration = Qpid::Messaging::Duration::FOREVER) message_impl = @receiver_impl.get duration.duration_impl create_message_wrapper message_impl unless message_impl.nil? @@ -79,33 +81,35 @@ module Qpid # Retrieves a message from the receiver's subscription, or waits # for up to the duration specified for one to become available. # - # If a block is given, then it will be invaked after the next message - # is received or the call times out, passing in the message or nil - # respectively. + # If no message is fetched within the specified time then a + # MessagingException is raised. # # ==== Options + # # * duration - the timeout to wait (def. Duration::FOREVER) # # ==== Examples # - # msg = rcvr.fetch # Uses the default timeout of forever - # - # msg = rcvr.fetch Qpid::Messaging::Duration::IMMEDIATE # returns a message or exits immediately - # - # # passes in a block to handle the received message - # rcvr.fetch Qpid::Messaging::Duration::SECOND do |message| - # if message.nil? - # puts "No message was received." - # else - # puts "Received this message: #{message.content}" - # end + # # retrieves a message, also handles exceptions raised on no messages + # begin + # # checks for a message, times out after one second + # msg = recv.fetch Qpid::Messaging::Duration::SECOND + # puts "Fetched this message: #{message.content}" + # rescue + # puts "No messages available. # end + # def fetch(duration = Qpid::Messaging::Duration::FOREVER) message_impl = @receiver_impl.fetch duration.duration_impl create_message_wrapper message_impl unless message_impl.nil? end - # Sets the capacity for this +Receiver+. + # Sets the capacity. + # + # The capacity of a +Receiver+ is the number of Messages that can be + # pre-fetched from the broker and held locally. If capacity is 0 then + # messages will never be pre-fetched and all messages must instead be + # retrieved using #fetch. # # ==== Options # @@ -113,63 +117,50 @@ module Qpid # # ==== Examples # - # receiver.capacity = 50 # sets the incoming capacity to 50 messages + # # create a receiver and give it a capacity of 50 + # recv = session.create_receiver "alerts/minor" + # recv.capacity = 50 # def capacity=(capacity); @receiver_impl.setCapacity capacity; end # Returns the capacity. - # - # - # The capacity is the numnber of incoming messages that can be held - # locally before being fetched. - # - # ==== Examples - # - # puts "The receiver can hold #{rcv.capacity} messages." - # def capacity; @receiver_impl.getCapacity; end - # Returns the number of slots for receiving messages. + # Returns the number of messages locally held. # - # This differs from +capacity+ in that it is the available slots in - # the capacity for holding incoming messages, where available <= capacity. + # The available is always 0 <= available <= capacity. + # + # If the #capacity is set to 0 then available will always be 0. # # ==== Examples # - # puts "You can receive #{rcv.available} messages before blocking." + # # output the number of messages waiting while processing + # loop do + # puts "There are #{recv.available} messages pending..." + # # wait forever (the default) for the next message + # msg = recv.get + # # process the message + # dispatch_message msg + # end # def available; @receiver_impl.getAvailable; end # Returns the number of messages that have been received and acknowledged # but whose acknowledgements have not been confirmed by the sender. - # - # ==== Examples - # - # puts "You have #{rcv.unsettled} messages to be confirmed." - # def unsettled; @receiver_impl.getUnsettled; end # Closes this +Receiver+. # - # This does not affect the +Session+. + # This does not affect the owning Session or Connection. def close; @receiver_impl.close; end - # Returns whether the receiver is closed. - # - # ==== Examples - # - # recv.close unless recv.closed? - # + # Returns whether the +Receiver+ is closed. def closed?; @receiver_impl.isClosed; end # Returns the name of this +Receiver+. - # - # ==== Examples - # - # puts "Receiver: #{recv.name}" def name; @receiver_impl.getName; end - # Returns the Session for this +Receiver+. + # Returns the owning Session for this +Receiver+. def session; @session; end private diff --git a/cpp/bindings/qpid/ruby/lib/qpid/sender.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/sender.rb index 97227622f5..4ce1393dc7 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/sender.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/sender.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,23 +15,39 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# +#++ module Qpid module Messaging - # Sender is the entity through which messages sent. + # +Sender+ is the entity through which messages are sent. # - # An instance of Sender can only be created using an active (not previously - # closed) Session. + # An instance of +Sender+ can only be created using an active (not previously + # closed) Session. See Qpid::Messaging::Session.create_sender for more details. # # ==== Examples # - # conn = Qpid::Messaging::Connection.new :url => "mybroker:5762" + # # create a connection + # conn = Qpid::Messaging::Connection.new "mybroker:5672" # conn.open - # session = conn.create_session - # sender = session.create_session "my-sender-queue;{create:always}" + # + # if conn.open? + # + # # create a session + # session = conn.create_session + # + # # create a sender that posts messages to the "updates" queue + # sender = session.create_sender "updates;{create:always} + # + # # begin sending updates + # loop do + # # wait for the next event content then send it + # content = wait_for_event + # sender.send Qpid::Messaging::Message.new :content => content + # end + # end + # class Sender def initialize(session, sender_impl) # :nodoc: @@ -43,15 +59,13 @@ module Qpid @sender_impl end - # Sends a message. - # - # If a block is given, then it will be invoked after the message - # is sent. + # Sends a message, optionally blocking until the message is received + # by the broker. # # ==== Options # - # * message - The message to send. - # * :sync - See note below on synching. + # * +message+ - The message to send. + # * +:sync+ - Block until received. See note below on synching. # # ==== Synching # @@ -61,9 +75,13 @@ module Qpid # # ==== Examples # - # sender.send message do |message| - # puts "Message sent: #{message.content}" - # end + # # send a message + # outgoing = Qpid::Messaging::Message.new :content => content + # sender.send outgoing + # + # # send a message, wait for confirmation from the broker + # outgoing = Qpid::Messaging::Message.new :content => content + # sender.send outgoing, :sync => true # def send(message, args = {}, &block) sync = args[:sync] || false @@ -73,52 +91,27 @@ module Qpid # Closes this +Sender+. # - # This does not affect the +Session+. + # This does not affect the owning Session or Connection. def close; @sender_impl.close; end # Returns the human-readable name for this +Sender+. - # - # ==== Examples - # - # puts "Sender: #{sender.name}" - # def name; @sender_impl.getName; end # Sets the capacity for this +Sender+. # # The capacity is the number of outgoing messages that can be held - # pending confirmation or receipt by the broker. + # pending confirmation of receipt by the broker. # # ==== Options # - # * capacity - the capacity - # - # ==== Examples - # - # sender.capacity = 50 # sets the outgoing capacity to 50 messages - # + # * +capacity+ - the capacity def capacity=(capacity); @sender_impl.setCapacity capacity; end # Returns the capacity. - # - # The capacity is the total number of outgoing messages that can be - # sent before a called to +send+ begins to block by default. - # - # ==== Examples - # - # puts "You can send a maximum of #{sender.capacity} messages." - # def capacity; @sender_impl.getCapacity; end # Returns the number of messages sent that are pending receipt # confirmation by the broker. - # - # ==== Examples - # - # if sender.unsettled > 0 - # puts "There are #{sender.unsettled} messages pending." - # end - # def unsettled; @sender_impl.getUnsettled; end # Returns the available slots for sending messages. @@ -127,21 +120,11 @@ module Qpid # the senders capacity for holding outgoing messages. The difference # between capacity and available is the number of messages that # have not been delivered yet. - # - # ==== Examples - # - # puts "You can send #{sender.available} messages before blocking." - # def available @sender_impl.getAvailable end - # Returns the +Session+ for this sender. - # - # ==== Examples - # - # recv.session.close if done - # + # Returns the Session for this sender. def session; @session; end end diff --git a/cpp/bindings/qpid/ruby/lib/qpid/session.rb b/cpp/bindings/qpid/ruby/lib/qpid_messaging/session.rb index feb8aa5bb4..7e6e11f654 100644 --- a/cpp/bindings/qpid/ruby/lib/qpid/session.rb +++ b/cpp/bindings/qpid/ruby/lib/qpid_messaging/session.rb @@ -1,4 +1,4 @@ -# +#-- # Licensed to the Apache Software Foundation (ASF) under one # or more contributor license agreements. See the NOTICE file # distributed with this work for additional information @@ -15,48 +15,41 @@ # KIND, either express or implied. See the License for the # specific language governing permissions and limitations # under the License. -# - -require 'cqpid' - -require 'qpid/errors' +#++ module Qpid module Messaging - # A Session represents a distinct conversation between end points. + # A +Session+ represents a distinct conversation between end points. They are + # created from an active (i.e., not closed) Connection. + # + # A +Session+ is used to acknowledge individual or all messages that have + # passed through it class Session def initialize(connection, session) # :nodoc: @connection = connection @session_impl = session - @senders = Hash.new - @receivers = Hash.new end def session_impl # :nodoc: @session_impl end - # Returns the +Connection+ associated with this session. + # Returns the Connection associated with this session. def connection @connection end # Creates a new endpoint for sending messages. # - # The +address+ can either be an instance +Address+ or else a - # string that describes an address endpoint. + # The address can either be an instance Address or else an + # address string. # # ==== Arguments # - # * +address+ The end point address. - # - # ==== Examples - # - # sender = session.create_sender "my-queue;{create:always}" - # + # * +address+ - the end point address. def create_sender(address) _address = address @@ -67,43 +60,28 @@ module Qpid sender_impl = @session_impl.createSender(_address) sender_name = sender_impl.getName - @senders[sender_name] = Qpid::Messaging::Sender.new(self, sender_impl) - - @senders[sender_name] + Qpid::Messaging::Sender.new(self, sender_impl) end - # Retrieves the +Sender+ with the specified name. + # Retrieves the Sender with the specified name. # - # The +Sender+ must have been previously created using - # the +create_sender+ method. + # Raises an exception if no such Sender exists. # # ==== Arguments # - # * +name+ The +Sender+ name. - # - # ==== Examples - # - # sender = session.sender "my-queue" - # + # * +name+ - the name of the Sender def sender(name) - raise Qpid::Messaging::KeyError, "No such sender: #{name}" unless @senders.has_key? name - - @senders[name] + Qpid::Messaging::Sender.new self, @session_impl.getSender(name) end # Creates a new endpoint for receiving messages. # - # The +address+ can either be an instance +Address+ or else a - # string that describes an address endpoint. + # The +address+ can either be an instance Address or else an + # address string. # # ==== Arguments # - # * +address+ The end point address. - # - # ==== Examples - # - # receiver = session.create_receiver "my-queue" - # + # * +address+ - the end point address. def create_receiver(address) result = nil receiver_impl = nil @@ -115,36 +93,24 @@ module Qpid receiver_impl = @session_impl.createReceiver(address) end - receiver_name = receiver_impl.getName - - @receivers[receiver_name] = Qpid::Messaging::Receiver.new self, receiver_impl - - @receivers[receiver_name] + Qpid::Messaging::Receiver.new self, receiver_impl end - # Retrieves the +Receiver+ with the specified name. - # - # The +Receiver+ must have been previously created using - # the +create_receiver+ method. + # Retrieves the +Receiver+ with the specified name, or nil if no such + # Receiver exists. # # ==== Arguments # - # * +name+ The +Receiver+ name. - # - # ==== Examples - # - # receiver = session.receiver "my-queue" - # + # * +name+ - the name of the Receiver def receiver(name) - raise Qpid::Messaging::KeyError, "No such receiver: #{name}" unless @receivers.has_key? name - - @receivers[name] + Qpid::Messaging::Receiver.new self, @session_impl.getReceiver(name) end # Closes the +Session+ and all associated +Sender+ and +Receiver+ instances. # - # NOTE: All +Session+ instances for a +Connection+ are closed when the - # +Connection+ is closed. + # *NOTE:* All +Session+ instances for a Connection are closed when the + # Connection is closed. But closing a +Session+ does not affect the + # owning Connection. def close; @session_impl.close; end # Commits any pending transactions for a transactional session. @@ -158,21 +124,30 @@ module Qpid # # ==== Arguments # - # * :message - if specified, then only the +Message+ specified is acknowledged - # * :sync - if true then the call will block until processed by the server (def. false) + # * +options+ - the set of options + # + # ==== Options + # + # * :message - if specified, then only that Message is acknowledged + # * :sync - if true, the call will block until processed by the broker # # ==== Examples # - # session.acknowledge # acknowledges all received messages - # session.acknowledge :message => message # acknowledge one message - # session.acknowledge :sync => true # blocks until the call completes + # # acknowledge all received messages + # session.acknowledge + # + # # acknowledge a single message + # session.acknowledge :message => message + # + # # acknowledge all messages, wait until the call finishes + # session.acknowledge :sync => true # #-- # TODO: Add an optional block to be used for blocking calls. #++ - def acknowledge(args = {}) - sync = args[:sync] || false - message = args[:message] if args[:message] + def acknowledge(options = {}) + sync = options[:sync] || false + message = options[:message] if options[:message] unless message.nil? @session_impl.acknowledge message.message_impl, sync @@ -193,11 +168,15 @@ module Qpid # NOTE: A message connot be released once it has been acknowled. def release(message); @session_impl.release message.message_impl; end - # Requests synchronization with the server. + # Requests synchronization with the broker. # # ==== Arguments # - # * :block - if true then the call blocks until the server acknowledges it (def. false) + # * +options+ - the list of options + # + # ==== Options + # + # * +:block+ - if true, the call blocks until the broker acknowledges it # #-- # TODO: Add an optional block to be used for blocking calls. @@ -208,26 +187,43 @@ module Qpid end # Returns the total number of receivable messages, and messages already - # received, by +Receiver+ instances associated with this +Session+. + # received, by Receiver instances associated with this +Session+. def receivable; @session_impl.getReceivable; end - # Returns the number of messages that have been acknowledged by this session - # whose acknowledgements have not been confirmed as processed by the server. + # Returns the number of messages that have been acknowledged by this + # +Session+ whose acknowledgements have not been confirmed as processed + # by the broker. def unsettled_acks; @session_impl.getUnsettledAcks; end - # Fetches the +Receiver+ for the next message. + # Fetches the next Receiver with a message pending. Waits the specified + # number of milliseconds before timing out. + # + # For a Receiver to be returned, it must have a capacity > 0 and have + # Messages locally queued. + # + # If no Receiver is found within the time out period, then a MessageError + # is raised. # # ==== Arguments # - # * timeout - time to wait for a +Receiver+ before timing out + # * +timeout+ - the duration # # ==== Examples # - # recv = session.next_receiver # wait forever for the next +Receiver+ - # # execute a block on the next receiver - # session.next_receiver do |recv| - # msg = recv.get - # puts "Received message: #{msg.content}" + # loop do + # + # begin + # # wait a maximum of one minute for the next receiver to be ready + # recv = session.next_receiver Qpid::Messaging::Duration::MINUTE + # + # # get and dispatch the message + # msg = recv.get + # dispatch_message msg + # + # rescue + # puts "No receivers were returned" + # end + # # end def next_receiver(timeout = Qpid::Messaging::Duration::FOREVER, &block) receiver_impl = @session_impl.nextReceiver(timeout.duration_impl) @@ -241,10 +237,6 @@ module Qpid end # Returns true if there were exceptions on this session. - # - # ==== Examples - # - # puts "There were session errors." if @session.errors? def errors?; @session_impl.hasError; end # If the +Session+ has been rendered invalid due to some exception, @@ -254,6 +246,7 @@ module Qpid # # ==== Examples # + # # show any errors that occurred during the Session # if @session.errors? # begin # @session.errors diff --git a/cpp/bindings/qpid/ruby/qpid_messaging.gemspec b/cpp/bindings/qpid/ruby/qpid_messaging.gemspec new file mode 100644 index 0000000000..06e3f48cb8 --- /dev/null +++ b/cpp/bindings/qpid/ruby/qpid_messaging.gemspec @@ -0,0 +1,28 @@ +# -*- encoding: utf-8 -*- +lib = File.expand_path('lib/', __FILE__) +$:.unshift lib unless $:.include?(lib) + +# Generate the Swig wrapper +system "swig -ruby -c++ -I../../../include -I../../ -o ext/cqpid/cqpid.cpp ruby.i" + +Gem::Specification.new do |s| + s.name = "qpid_messaging" + s.version = "0.22.0" + s.platform = Gem::Platform::RUBY + s.authors = "Apache Qpid Project" + s.email = "dev@qpid.apache.org" + s.homepage = "http://qpid.apache.org" + s.summary = "Qpid is an enterprise messaging framework." + s.description = s.summary + + s.extensions = "ext/cqpid/extconf.rb" + s.files = Dir["LICENSE", + "ChangeLog", + "README.rdoc", + "TODO", + "lib/**/*.rb", + "ext/**/*", + ] + s.require_path = 'lib' +end + diff --git a/cpp/bindings/qpid/ruby/ruby.i b/cpp/bindings/qpid/ruby/ruby.i index 76463f7ddd..3d686c2ddb 100644 --- a/cpp/bindings/qpid/ruby/ruby.i +++ b/cpp/bindings/qpid/ruby/ruby.i @@ -18,8 +18,10 @@ */ %module cqpid +/* Ruby doesn't have a != operator*/ +#pragma SWIG nowarn=378 %include "std_string.i" -%include "../../swig_ruby_typemaps.i" +%include "qpid/swig_ruby_typemaps.i" /* Define the general-purpose exception handling */ %exception { @@ -32,5 +34,5 @@ } } -%include "../qpid.i" +%include "qpid/qpid.i" diff --git a/cpp/bindings/qpid/ruby/spec/qpid/address_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/address_spec.rb index 784fb6fe77..05c97ddf30 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/address_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/address_spec.rb @@ -26,7 +26,7 @@ module Qpid describe Address do before(:each) do - @address = Qpid::Messaging::Address.new "my-name", "my-subject", :create => :always + @address = Qpid::Messaging::Address.new "my-name/my-subject;{create:always}" end it "stores the name, subject and options when created" do @@ -72,7 +72,7 @@ module Qpid end it "can return a string representation" do - address = Qpid::Messaging::Address.new "foo", "bar", :create => :always, :link => :durable + address = Qpid::Messaging::Address.new "foo/bar:{create:always,link:durable}" result = address.to_s result.should =~ /foo\/bar/ diff --git a/cpp/bindings/qpid/ruby/spec/qpid/connection_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/connection_spec.rb index a2f5b7e898..811abf36e9 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/connection_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/connection_spec.rb @@ -37,7 +37,7 @@ module Qpid connection = Qpid::Messaging::Connection.new :options => {:username => "foo"} connection.options.should include("username") - }.should_not raise_error + }.to_not raise_error end it "returns the underlying implementation" do diff --git a/cpp/bindings/qpid/ruby/spec/qpid/duration_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/duration_spec.rb index 4980b6ffe7..202332d232 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/duration_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/duration_spec.rb @@ -49,6 +49,33 @@ module Qpid milliseconds.should == 1000 end + it "raises an error when multiplied by a negative" do + expect { + twomin = Qpid::Messaging::Duration::MINUTE * -2 + }.to raise_error + end + + it "returns IMMEDIATE if the factor is zero" do + result = Qpid::Messaging::Duration::MINUTE * 0 + result.should be(Qpid::Messaging::Duration::IMMEDIATE) + end + + it "fractional factors return a reduced duration" do + factor = rand(1) + first = Qpid::Messaging::Duration::MINUTE + second = first * factor + + second.milliseconds.should == ((first.milliseconds * factor).floor) + end + + it "can return a multiple of its duration" do + factor = rand(10).floor + first = Qpid::Messaging::Duration.new(rand(10).floor * 10000) + second = first * factor + + second.milliseconds.should == first.milliseconds * factor + end + end end diff --git a/cpp/bindings/qpid/ruby/spec/qpid/encoding_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/encoding_spec.rb index 58b8447278..58b8447278 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/encoding_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/encoding_spec.rb diff --git a/cpp/bindings/qpid/ruby/spec/qpid/message_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/message_spec.rb index e34e58f563..be19b3591e 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/message_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/message_spec.rb @@ -36,7 +36,7 @@ module Qpid end it "can set the reply to address" do - address = Qpid::Messaging::Address.new "my-queue", "" + address = Qpid::Messaging::Address.new "my-queue;{create:always}" @message.reply_to = address @@ -45,6 +45,19 @@ module Qpid reply_to.name.should == address.name end + it "can set the reply to from an address string" do + name = "my-queue" + subject = "responses" + address = "#{name}/#{subject}" + + @message.reply_to = address + + reply_to = @message.reply_to + + reply_to.name.should == name + reply_to.subject.should == subject + end + it "should store the content when created" do content = @message.content diff --git a/cpp/bindings/qpid/ruby/spec/qpid/receiver_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/receiver_spec.rb index 81ae935dcb..81ae935dcb 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/receiver_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/receiver_spec.rb diff --git a/cpp/bindings/qpid/ruby/spec/qpid/sender_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/sender_spec.rb index fa3a2a5b1f..fa3a2a5b1f 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/sender_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/sender_spec.rb diff --git a/cpp/bindings/qpid/ruby/spec/qpid/session_spec.rb b/cpp/bindings/qpid/ruby/spec/qpid_messaging/session_spec.rb index 0b103a31e6..754e2ca88f 100644 --- a/cpp/bindings/qpid/ruby/spec/qpid/session_spec.rb +++ b/cpp/bindings/qpid/ruby/spec/qpid_messaging/session_spec.rb @@ -46,7 +46,7 @@ module Qpid end it "creates a Sender from an Address" do - address = Qpid::Messaging::Address.new "my-queu", "", :create => :always + address = Qpid::Messaging::Address.new "my-queue;{create:always}" @session_impl.should_receive(:createSender). with(address.address_impl). diff --git a/cpp/bindings/qpid/ruby/spec/spec_helper.rb b/cpp/bindings/qpid/ruby/spec/spec_helper.rb index 90084963f4..865e60e0e2 100644 --- a/cpp/bindings/qpid/ruby/spec/spec_helper.rb +++ b/cpp/bindings/qpid/ruby/spec/spec_helper.rb @@ -17,5 +17,4 @@ # under the License. # -require 'qpid' -require 'cqpid' +require 'qpid_messaging' diff --git a/cpp/bindings/swig_perl_typemaps.i b/cpp/bindings/swig_perl_typemaps.i deleted file mode 100644 index 831576a7d4..0000000000 --- a/cpp/bindings/swig_perl_typemaps.i +++ /dev/null @@ -1,330 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%wrapper %{ - -#include <stdarg.h> - - SV* MapToPerl(const qpid::types::Variant::Map*); - SV* ListToPerl(const qpid::types::Variant::List*); - void PerlToMap(SV*, qpid::types::Variant::Map*); - void PerlToList(SV*, qpid::types::Variant::List*); - - qpid::types::Variant PerlToVariant(SV* value) { - if (SvROK(value)) { - if (SvTYPE(SvRV(value)) == SVt_PVHV) { - qpid::types::Variant::Map map; - PerlToMap(value, &map); - return qpid::types::Variant(map); - } - else if (SvTYPE(SvRV(value)) == SVt_PVAV) { - qpid::types::Variant::List list; - PerlToList(value, &list); - return qpid::types::Variant(list); - } - } - else { - if (SvIOK(value)) { - return qpid::types::Variant((int64_t) SvIV(value)); - } - else if (SvNOK(value)) { - return qpid::types::Variant((float)SvNV(value)); - } - else if (SvPOK(value)) { - return qpid::types::Variant(std::string(SvPV_nolen(value))); - } - } - return qpid::types::Variant(); - } - - SV* VariantToPerl(const qpid::types::Variant* v) { - SV* result = newSV(0); - try { - switch (v->getType()) { - case qpid::types::VAR_VOID: { - sv_setiv(result, (IV)0); - break; - } - case qpid::types::VAR_BOOL : { - result = boolSV(v->asBool()); - break; - } - case qpid::types::VAR_UINT8 : - case qpid::types::VAR_UINT16 : - case qpid::types::VAR_UINT32 : { - sv_setuv(result, (UV)v->asUint32()); - break; - } - case qpid::types::VAR_UINT64 : { - sv_setuv(result, (UV)v->asUint64()); - break; - } - case qpid::types::VAR_INT8 : - case qpid::types::VAR_INT16 : - case qpid::types::VAR_INT32 : { - sv_setiv(result, (IV)v->asInt32()); - break; - } - case qpid::types::VAR_INT64 : { - sv_setiv(result, (IV)v->asInt64()); - break; - } - case qpid::types::VAR_FLOAT : { - sv_setnv(result, (double)v->asFloat()); - break; - } - case qpid::types::VAR_DOUBLE : { - sv_setnv(result, (double)v->asDouble()); - break; - } - case qpid::types::VAR_STRING : { - const std::string val(v->asString()); - result = newSVpvn(val.c_str(), val.size()); - break; - } - case qpid::types::VAR_MAP : { - result = MapToPerl(&(v->asMap())); - break; - } - case qpid::types::VAR_LIST : { - result = ListToPerl(&(v->asList())); - break; - } - case qpid::types::VAR_UUID : { - } - } - } catch (qpid::types::Exception& ex) { - Perl_croak(aTHX_ ex.what()); - } - - return result; - } - - SV* MapToPerl(const qpid::types::Variant::Map* map) { - SV *result = newSV(0); - HV *hv = (HV *)sv_2mortal((SV *)newHV()); - qpid::types::Variant::Map::const_iterator iter; - for (iter = map->begin(); iter != map->end(); iter++) { - const std::string key(iter->first); - SV* perlval = VariantToPerl(&(iter->second)); - hv_store(hv, key.c_str(), key.size(), perlval, 0); - } - SvSetSV(result, newRV_noinc((SV *)hv)); - return result; - } - - SV* ListToPerl(const qpid::types::Variant::List* list) { - SV* result = newSV(0); - AV* av = (AV *)sv_2mortal((SV *)newAV()); - qpid::types::Variant::List::const_iterator iter; - for (iter = list->begin(); iter != list->end(); iter++) { - SV* perlval = VariantToPerl(&(*iter)); - av_push(av, perlval); - } - SvSetSV(result, newRV_noinc((SV *)av)); - return result; - } - - void PerlToMap(SV* hash, qpid::types::Variant::Map* map) { - map->clear(); - HV* hv = (HV *)SvRV(hash); - HE* he; - while((he = hv_iternext(hv)) != NULL) { - SV* svkey = HeSVKEY_force(he); - SV* svval = HeVAL(he); - (*map)[std::string(SvPV_nolen(svkey))] = PerlToVariant(svval); - } - } - - void PerlToList(SV* ary, qpid::types::Variant::List* list) { - list->clear(); - AV * av = (AV *)SvRV(ary); - I32 len = av_len(av) + 1; - if (len > 0) { - for (I32 i = 0; i < len; i++) { - list->push_back(PerlToVariant(*av_fetch(av, i, 0))); - } - } - } -%} - -%typemap (in) void * { - $1 = (void *)SvIV($input); -} - -%typemap (out) void * { - sv_setiv($result, (IV)$1); - argvi++; -} - -%typemap (in) uint16_t, uint32_t, uint64_t { - if (SvIOK($input)) { - $1 = ($1_ltype)SvUV($input); - } - else { - SWIG_exception_fail(SWIG_ValueError, "not an integer"); - } -} - -%typemap (out) uint16_t, uint32_t, uint64_t { - sv_setuv($result, (UV)$1); - argvi++; -} - -%typemap (in) int32_t, int64_t { - if (SvIOK($input)) { - $1 = ($1_ltype)SvIV($input); - } - else { - SWIG_exception_fail(SWIG_ValueError, "not an integer"); - } -} - -%typemap (out) int32_t, int64_t { - sv_setiv($result, (IV)$1); - argvi++; -} - -%typemap(in) bool { - $1 = (bool)SvTRUE($input); -} - -%typemap (out) bool { - $result = boolSV($1); - argvi++; -} - - -%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT64) uint64_t { - $1 = SvIOK($input) ? 1 : 0; -} - -%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT32) uint32_t { - $1 = SvIOK($input) ? 1 : 0; -} - - -/* - * Variant types: C++ --> Perl - */ -%typemap(out) qpid::types::Variant::Map { - $result = MapToPerl(&$1); - argvi++; -} - -%typemap(out) qpid::types::Variant::Map& { - $result = MapToPerl($1); - argvi++; -} - -%typemap(out) qpid::types::Variant::List { - $result = ListToPerl(&$1); - argvi++; -} - -%typemap(out) qpid::types::Variant::List& { - $result = ListToPerl($1); - argvi++; -} - -%typemap(out) qpid::types::Variant& { - $result = VariantToPerl($1); - argvi++; -} - - -/* - * Variant types: Perl --> C++ - */ -%typemap(in) qpid::types::Variant& { - $1 = new qpid::types::Variant(PerlToVariant($input)); -} - -%typemap(in) qpid::types::Variant::Map& { - $1 = new qpid::types::Variant::Map(); - PerlToMap($input, $1); - -} - -%typemap(in) qpid::types::Variant::List& { - $1 = new qpid::types::Variant::List(); - PerlToList($input, $1); - -} - -%typemap(in) const qpid::types::Variant::Map const & { - $1 = new qpid::types::Variant::Map(); - PerlToMap($input, $1); -} - -%typemap(in) const qpid::types::Variant::List const & { - $1 = new qpid::types::Variant::List(); - PerlToList($input, $1); -} - -%typemap(freearg) qpid::types::Variant& { - delete $1; -} - -%typemap(freearg) qpid::types::Variant::Map& { - delete $1; -} - -%typemap(freearg) qpid::types::Variant::List& { - delete $1; -} - - -/* - * Variant types: typecheck maps - */ -%typemap(typecheck) qpid::types::Variant::Map& { - $1 = (SvTYPE(SvRV($input)) == SVt_PVHV) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant::List& { - $1 = (SvTYPE(SvRV($input)) == SVt_PVAV) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant& { - $1 = (SvIOK($input) || - SvNOK($input) || - SvPOK($input) ) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant::Map const & { - $1 = (SvTYPE(SvRV($input)) == SVt_PVHV) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant::List const & { - $1 = (SvTYPE(SvRV($input)) == SVt_PVAV) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant const & { - $1 = (SvIOK($input) || - SvNOK($input) || - SvPOK($input) ) ? 1 : 0; -} - -/* No boolean type for perl. - Boolean is simply and integer in perl -*/ -%typecheck(SWIG_TYPECHECK_BOOL) bool { - $1 = (SvIOK($input)) ? 1 : 0; -} diff --git a/cpp/bindings/swig_python_typemaps.i b/cpp/bindings/swig_python_typemaps.i deleted file mode 100644 index 25a4e46b18..0000000000 --- a/cpp/bindings/swig_python_typemaps.i +++ /dev/null @@ -1,446 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -/* For UUID objects, to convert them to Python uuid.UUID objects, - * we'll need a reference to the uuid module. - */ -%{ -static PyObject* pUuidModule; -%} - -%init %{ - /* Instead of directly referencing the uuid module (which is not available - * on older versions of Python), reference the wrapper defined in - * qpid.datatypes. - */ - pUuidModule = PyImport_ImportModule("qpid.datatypes"); - - /* Although it is not required, we'll publish the uuid module in our - * module, as if this module was a python module and we called - * "import uuid" - */ - Py_INCREF(pUuidModule); - PyModule_AddObject(m, "uuid", pUuidModule); -%} - - -%wrapper %{ - -#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) -typedef int Py_ssize_t; -#define PY_SSIZE_T_MAX INT_MAX -#define PY_SSIZE_T_MIN INT_MIN -#endif - - - PyObject* MapToPy(const qpid::types::Variant::Map*); - PyObject* ListToPy(const qpid::types::Variant::List*); - PyObject* UuidToPy(const qpid::types::Uuid*); - void PyToMap(PyObject*, qpid::types::Variant::Map*); - void PyToList(PyObject*, qpid::types::Variant::List*); - - qpid::types::Variant PyToVariant(PyObject* value) { - if (PyBool_Check(value)) return qpid::types::Variant(bool(PyInt_AS_LONG(value) ? true : false)); - if (PyFloat_Check(value)) return qpid::types::Variant(PyFloat_AS_DOUBLE(value)); - if (PyInt_Check(value)) return qpid::types::Variant(int64_t(PyInt_AS_LONG(value))); - if (PyLong_Check(value)) return qpid::types::Variant(int64_t(PyLong_AsLongLong(value))); - if (PyString_Check(value)) return qpid::types::Variant(std::string(PyString_AS_STRING(value))); - if (PyDict_Check(value)) { - qpid::types::Variant::Map map; - PyToMap(value, &map); - return qpid::types::Variant(map); - } - if (PyList_Check(value)) { - qpid::types::Variant::List list; - PyToList(value, &list); - return qpid::types::Variant(list); - } - return qpid::types::Variant(); - } - - PyObject* VariantToPy(const qpid::types::Variant* v) { - PyObject* result; - try { - switch (v->getType()) { - case qpid::types::VAR_VOID: { - result = Py_None; - break; - } - case qpid::types::VAR_BOOL : { - result = v->asBool() ? Py_True : Py_False; - break; - } - case qpid::types::VAR_UINT8 : - case qpid::types::VAR_UINT16 : - case qpid::types::VAR_UINT32 : { - result = PyInt_FromLong((long) v->asUint32()); - break; - } - case qpid::types::VAR_UINT64 : { - result = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG) v->asUint64()); - break; - } - case qpid::types::VAR_INT8 : - case qpid::types::VAR_INT16 : - case qpid::types::VAR_INT32 : { - result = PyInt_FromLong((long) v->asInt32()); - break; - } - case qpid::types::VAR_INT64 : { - result = PyLong_FromLongLong((PY_LONG_LONG) v->asInt64()); - break; - } - case qpid::types::VAR_FLOAT : { - result = PyFloat_FromDouble((double) v->asFloat()); - break; - } - case qpid::types::VAR_DOUBLE : { - result = PyFloat_FromDouble((double) v->asDouble()); - break; - } - case qpid::types::VAR_STRING : { - const std::string val(v->asString()); - result = PyString_FromStringAndSize(val.c_str(), val.size()); - break; - } - case qpid::types::VAR_MAP : { - result = MapToPy(&(v->asMap())); - break; - } - case qpid::types::VAR_LIST : { - result = ListToPy(&(v->asList())); - break; - } - case qpid::types::VAR_UUID : { - qpid::types::Uuid uuid = v->asUuid(); - result = UuidToPy(&uuid); - break; - } - } - } catch (qpid::types::Exception& ex) { - PyErr_SetString(PyExc_RuntimeError, ex.what()); - result = 0; - } - - return result; - } - - PyObject* MapToPy(const qpid::types::Variant::Map* map) { - PyObject* result = PyDict_New(); - qpid::types::Variant::Map::const_iterator iter; - for (iter = map->begin(); iter != map->end(); iter++) { - const std::string key(iter->first); - PyObject* pyval = VariantToPy(&(iter->second)); - if (pyval == 0) - return 0; - PyDict_SetItem(result, PyString_FromStringAndSize(key.c_str(), key.size()), pyval); - } - return result; - } - - PyObject* ListToPy(const qpid::types::Variant::List* list) { - PyObject* result = PyList_New(list->size()); - qpid::types::Variant::List::const_iterator iter; - Py_ssize_t idx(0); - for (iter = list->begin(); iter != list->end(); iter++) { - PyObject* pyval = VariantToPy(&(*iter)); - if (pyval == 0) - return 0; - PyList_SetItem(result, idx, pyval); - idx++; - } - return result; - } - - PyObject* UuidToPy(const qpid::types::Uuid * uuid) { - PyObject* pUuidClass = PyObject_GetAttrString(pUuidModule, "UUID"); - if (!pUuidClass) { - // Failed to get UUID class - return 0; - } - - PyObject* pArgs = PyTuple_New(0); - PyObject* pKw = PyDict_New(); - PyObject* pData = PyString_FromStringAndSize( - (const char*)(uuid->data()), 16); - PyDict_SetItemString(pKw, "bytes", pData); - - PyObject* result = PyObject_Call(pUuidClass, pArgs, pKw); - - Py_DECREF(pData); - Py_DECREF(pKw); - Py_DECREF(pArgs); - Py_DECREF(pUuidClass); - - return result; - } - - - void PyToMap(PyObject* obj, qpid::types::Variant::Map* map) { - map->clear(); - Py_ssize_t iter(0); - PyObject *key; - PyObject *val; - while (PyDict_Next(obj, &iter, &key, &val)) - (*map)[std::string(PyString_AS_STRING(key))] = PyToVariant(val); - } - - void PyToList(PyObject* obj, qpid::types::Variant::List* list) { - list->clear(); - Py_ssize_t count(PyList_Size(obj)); - for (Py_ssize_t idx = 0; idx < count; idx++) - list->push_back(PyToVariant(PyList_GetItem(obj, idx))); - } - -%} - - -/* unsigned32 Convert from Python --> C */ -%typemap(in) uint32_t { - if (PyInt_Check($input)) { - $1 = (uint32_t) PyInt_AsUnsignedLongMask($input); - } else if (PyLong_Check($input)) { - $1 = (uint32_t) PyLong_AsUnsignedLong($input); - } else { - SWIG_exception_fail(SWIG_ValueError, "unknown integer type"); - } -} - -/* unsinged32 Convert from C --> Python */ -%typemap(out) uint32_t { - $result = PyInt_FromLong((long)$1); -} - - -/* unsigned16 Convert from Python --> C */ -%typemap(in) uint16_t { - if (PyInt_Check($input)) { - $1 = (uint16_t) PyInt_AsUnsignedLongMask($input); - } else if (PyLong_Check($input)) { - $1 = (uint16_t) PyLong_AsUnsignedLong($input); - } else { - SWIG_exception_fail(SWIG_ValueError, "unknown integer type"); - } -} - -/* unsigned16 Convert from C --> Python */ -%typemap(out) uint16_t { - $result = PyInt_FromLong((long)$1); -} - - -/* signed32 Convert from Python --> C */ -%typemap(in) int32_t { - if (PyInt_Check($input)) { - $1 = (int32_t) PyInt_AsLong($input); - } else if (PyLong_Check($input)) { - $1 = (int32_t) PyLong_AsLong($input); - } else { - SWIG_exception_fail(SWIG_ValueError, "unknown integer type"); - } -} - -/* signed32 Convert from C --> Python */ -%typemap(out) int32_t { - $result = PyInt_FromLong((long)$1); -} - - -/* unsigned64 Convert from Python --> C */ -%typemap(in) uint64_t { -%#ifdef HAVE_LONG_LONG - if (PyLong_Check($input)) { - $1 = (uint64_t)PyLong_AsUnsignedLongLong($input); - } else if (PyInt_Check($input)) { - $1 = (uint64_t)PyInt_AsUnsignedLongLongMask($input); - } else -%#endif - { - SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - uint64_t input too large"); - } -} - -/* unsigned64 Convert from C --> Python */ -%typemap(out) uint64_t { -%#ifdef HAVE_LONG_LONG - $result = PyLong_FromUnsignedLongLong((unsigned PY_LONG_LONG)$1); -%#else - SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - uint64_t output too large"); -%#endif -} - -/* signed64 Convert from Python --> C */ -%typemap(in) int64_t { -%#ifdef HAVE_LONG_LONG - if (PyLong_Check($input)) { - $1 = (int64_t)PyLong_AsLongLong($input); - } else if (PyInt_Check($input)) { - $1 = (int64_t)PyInt_AsLong($input); - } else -%#endif - { - SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - int64_t input too large"); - } -} - -/* signed64 Convert from C --> Python */ -%typemap(out) int64_t { -%#ifdef HAVE_LONG_LONG - $result = PyLong_FromLongLong((PY_LONG_LONG)$1); -%#else - SWIG_exception_fail(SWIG_ValueError, "unsupported integer size - int64_t output too large"); -%#endif -} - - -/* Convert from Python --> C */ -%typemap(in) void * { - $1 = (void *)$input; -} - -/* Convert from C --> Python */ -%typemap(out) void * { - $result = (PyObject *) $1; - Py_INCREF($result); -} - -/* - * Variant types: C++ --> Python - */ -%typemap(out) qpid::types::Variant::Map { - $result = MapToPy(&$1); -} - -%typemap(out) qpid::types::Variant::Map& { - $result = MapToPy($1); -} - -%typemap(out) qpid::types::Variant::List { - $result = ListToPy(&$1); -} - -%typemap(out) qpid::types::Variant::List& { - $result = ListToPy($1); -} - -%typemap(out) qpid::types::Variant& { - $result = VariantToPy($1); -} - -/* - * UUID type: C++ --> Python - */ -%typemap(out) qpid::types::UUID & { - $result = UuidToPy($1); -} - - -/* - * Variant types: Ruby --> C++ - */ -%typemap(in) qpid::types::Variant& { - $1 = new qpid::types::Variant(PyToVariant($input)); -} - -%typemap(in) qpid::types::Variant::Map& { - $1 = new qpid::types::Variant::Map(); - PyToMap($input, $1); -} - -%typemap(in) qpid::types::Variant::List& { - $1 = new qpid::types::Variant::List(); - PyToList($input, $1); -} - -%typemap(in) const qpid::types::Variant::Map const & { - $1 = new qpid::types::Variant::Map(); - PyToMap($input, $1); -} - -%typemap(in) const qpid::types::Variant::List const & { - $1 = new qpid::types::Variant::List(); - PyToList($input, $1); -} - -%typemap(freearg) qpid::types::Variant& { - delete $1; -} - -%typemap(freearg) qpid::types::Variant::Map& { - delete $1; -} - -%typemap(freearg) qpid::types::Variant::List& { - delete $1; -} - - -/* - * Variant types: typecheck maps - */ -%typemap(typecheck) qpid::types::Variant::Map& { - $1 = PyDict_Check($input) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant::List& { - $1 = PyList_Check($input) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant& { - $1 = (PyFloat_Check($input) || - PyString_Check($input) || - PyInt_Check($input) || - PyLong_Check($input) || - PyDict_Check($input) || - PyList_Check($input) || - PyBool_Check($input)) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant::Map const & { - $1 = PyDict_Check($input) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant::List const & { - $1 = PyList_Check($input) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant const & { - $1 = (PyFloat_Check($input) || - PyString_Check($input) || - PyInt_Check($input) || - PyLong_Check($input) || - PyDict_Check($input) || - PyList_Check($input) || - PyBool_Check($input)) ? 1 : 0; -} - -%typemap(typecheck) bool { - $1 = PyBool_Check($input) ? 1 : 0; -} - - - -%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT64) uint64_t { - $1 = PyLong_Check($input) ? 1 : 0; -} - -%typemap (typecheck, precedence=SWIG_TYPECHECK_UINT32) uint32_t { - $1 = PyInt_Check($input) ? 1 : 0; -} - diff --git a/cpp/bindings/swig_ruby_typemaps.i b/cpp/bindings/swig_ruby_typemaps.i deleted file mode 100644 index 1a07cc86b0..0000000000 --- a/cpp/bindings/swig_ruby_typemaps.i +++ /dev/null @@ -1,368 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one - * or more contributor license agreements. See the NOTICE file - * distributed with this work for additional information - * regarding copyright ownership. The ASF licenses this file - * to you under the Apache License, Version 2.0 (the - * "License"); you may not use this file except in compliance - * with the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, - * software distributed under the License is distributed on an - * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY - * KIND, either express or implied. See the License for the - * specific language governing permissions and limitations - * under the License. - */ - -%wrapper %{ - -#include <stdarg.h> - - VALUE MapToRb(const qpid::types::Variant::Map*); - VALUE ListToRb(const qpid::types::Variant::List*); - void RbToMap(VALUE, qpid::types::Variant::Map*); - void RbToList(VALUE, qpid::types::Variant::List*); - - qpid::types::Variant RbToVariant(VALUE value) { - switch (TYPE(value)) { - case T_FLOAT: return qpid::types::Variant(NUM2DBL(value)); - case T_STRING: return qpid::types::Variant(StringValuePtr(value)); - case T_FIXNUM: return qpid::types::Variant((int64_t) FIX2LONG(value)); - case T_BIGNUM: return qpid::types::Variant((int64_t) NUM2LL(value)); - case T_TRUE: return qpid::types::Variant(true); - case T_FALSE: return qpid::types::Variant(false); - case T_HASH: { - qpid::types::Variant::Map map; - RbToMap(value, &map); - return qpid::types::Variant(map); - } - case T_ARRAY: { - qpid::types::Variant::List list; - RbToList(value, &list); - return qpid::types::Variant(list); - } - default: return qpid::types::Variant(); - } - } - - VALUE VariantToRb(const qpid::types::Variant* v) { - VALUE result = Qnil; - try { - switch (v->getType()) { - case qpid::types::VAR_VOID: { - result = Qnil; - break; - } - case qpid::types::VAR_BOOL : { - result = v->asBool() ? Qtrue : Qfalse; - break; - } - case qpid::types::VAR_UINT8 : - case qpid::types::VAR_UINT16 : - case qpid::types::VAR_UINT32 : { - result = UINT2NUM(v->asUint32()); - break; - } - case qpid::types::VAR_UINT64 : { - result = ULL2NUM(v->asUint64()); - break; - } - case qpid::types::VAR_INT8 : - case qpid::types::VAR_INT16 : - case qpid::types::VAR_INT32 : { - result = INT2NUM(v->asInt32()); - break; - } - case qpid::types::VAR_INT64 : { - result = LL2NUM(v->asInt64()); - break; - } - case qpid::types::VAR_FLOAT : { - result = rb_float_new((double) v->asFloat()); - break; - } - case qpid::types::VAR_DOUBLE : { - result = rb_float_new(v->asDouble()); - break; - } - case qpid::types::VAR_STRING : { - const std::string val(v->asString()); - result = rb_str_new(val.c_str(), val.size()); - break; - } - case qpid::types::VAR_MAP : { - result = MapToRb(&(v->asMap())); - break; - } - case qpid::types::VAR_LIST : { - result = ListToRb(&(v->asList())); - break; - } - case qpid::types::VAR_UUID : { - } - } - } catch (qpid::types::Exception& ex) { - static VALUE error = rb_define_class("Error", rb_eStandardError); - rb_raise(error, ex.what()); - } - - return result; - } - - VALUE MapToRb(const qpid::types::Variant::Map* map) { - VALUE result = rb_hash_new(); - qpid::types::Variant::Map::const_iterator iter; - for (iter = map->begin(); iter != map->end(); iter++) { - const std::string key(iter->first); - VALUE rbval = VariantToRb(&(iter->second)); - rb_hash_aset(result, rb_str_new(key.c_str(), key.size()), rbval); - } - return result; - } - - VALUE ListToRb(const qpid::types::Variant::List* list) { - VALUE result = rb_ary_new2(list->size()); - qpid::types::Variant::List::const_iterator iter; - for (iter = list->begin(); iter != list->end(); iter++) { - VALUE rbval = VariantToRb(&(*iter)); - rb_ary_push(result, rbval); - } - return result; - } - - VALUE HashIter(VALUE data_ary, VALUE context) { - VALUE key = rb_ary_entry(data_ary, 0); - VALUE val = rb_ary_entry(data_ary, 1); - qpid::types::Variant::Map* map((qpid::types::Variant::Map*) context); - (*map)[std::string(StringValuePtr(key))] = RbToVariant(val); - return data_ary; - } - - VALUE AryIter(VALUE data, VALUE context) { - qpid::types::Variant::List* list((qpid::types::Variant::List*) context); - list->push_back(RbToVariant(data)); - return data; - } - - void RbToMap(VALUE hash, qpid::types::Variant::Map* map) { - map->clear(); - rb_iterate(rb_each, hash, (VALUE(*)(ANYARGS))HashIter, (VALUE) map); - } - - void RbToList(VALUE ary, qpid::types::Variant::List* list) { - list->clear(); - rb_iterate(rb_each, ary, (VALUE(*)(ANYARGS))AryIter, (VALUE) list); - } -%} - -%typemap (in) void * -{ - $1 = (void *) $input; -} - -%typemap (out) void * -{ - $result = (VALUE) $1; -} - -%typemap (in) uint8_t -{ - $1 = NUM2UINT ($input); -} - -%typemap (out) uint8_t -{ - $result = UINT2NUM((uint8_t) $1); -} - -%typemap (in) int8_t -{ - $1 = NUM2INT ($input); -} - -%typemap (out) int8_t -{ - $result = INT2NUM((int8_t) $1); -} - -%typemap (in) uint16_t -{ - $1 = NUM2UINT ($input); -} - -%typemap (out) uint16_t -{ - $result = UINT2NUM((uint16_t) $1); -} - -%typemap (in) uint32_t -{ - if (TYPE($input) == T_BIGNUM) - $1 = NUM2UINT($input); - else - $1 = FIX2UINT($input); -} - -%typemap (out) uint32_t -{ - $result = UINT2NUM((uint32_t) $1); -} - -%typemap (in) int32_t -{ - if (TYPE($input) == T_BIGNUM) - $1 = NUM2INT($input); - else - $1 = FIX2INT($input); -} - -%typemap (out) int32_t -{ - $result = INT2NUM((int32_t) $1); -} - -%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint32_t { - $1 = FIXNUM_P($input); -} - -%typemap (in) uint64_t -{ - if (TYPE($input) == T_BIGNUM) - $1 = NUM2ULL($input); - else - $1 = (uint64_t) FIX2ULONG($input); -} - -%typemap (out) uint64_t -{ - $result = ULL2NUM((uint64_t) $1); -} - -%typemap (in) int64_t -{ - if (TYPE($input) == T_BIGNUM) - $1 = NUM2LL($input); - else - $1 = (int64_t) FIX2LONG($input); -} - -%typemap (out) int64_t -{ - $result = LL2NUM((int64_t) $1); -} - -/* - * Variant types: C++ --> Ruby - */ -%typemap(out) qpid::types::Variant::Map { - $result = MapToRb(&$1); -} - -%typemap(out) qpid::types::Variant::Map& { - $result = MapToRb($1); -} - -%typemap(out) qpid::types::Variant::List { - $result = ListToRb(&$1); -} - -%typemap(out) qpid::types::Variant::List& { - $result = ListToRb($1); -} - -%typemap(out) qpid::types::Variant& { - $result = VariantToRb($1); -} - - -/* - * Variant types: Ruby --> C++ - */ -%typemap(in) qpid::types::Variant& { - $1 = new qpid::types::Variant(RbToVariant($input)); -} - -%typemap(in) qpid::types::Variant::Map& { - $1 = new qpid::types::Variant::Map(); - RbToMap($input, $1); -} - -%typemap(in) qpid::types::Variant::List& { - $1 = new qpid::types::Variant::List(); - RbToList($input, $1); -} - -%typemap(in) const qpid::types::Variant::Map const & { - $1 = new qpid::types::Variant::Map(); - RbToMap($input, $1); -} - -%typemap(in) const qpid::types::Variant::List const & { - $1 = new qpid::types::Variant::List(); - RbToList($input, $1); -} - -%typemap(freearg) qpid::types::Variant& { - delete $1; -} - -%typemap(freearg) qpid::types::Variant::Map& { - delete $1; -} - -%typemap(freearg) qpid::types::Variant::List& { - delete $1; -} - - -/* - * Variant types: typecheck maps - */ -%typemap(typecheck) qpid::types::Variant::Map& { - $1 = (TYPE($input) == T_HASH) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant::List& { - $1 = (TYPE($input) == T_ARRAY) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant& { - $1 = (TYPE($input) == T_FLOAT || - TYPE($input) == T_STRING || - TYPE($input) == T_FIXNUM || - TYPE($input) == T_BIGNUM || - TYPE($input) == T_TRUE || - TYPE($input) == T_FALSE) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant::Map const & { - $1 = (TYPE($input) == T_HASH) ? 1 : 0; -} - -%typemap(typecheck) qpid::types::Variant::List const & { - $1 = (TYPE($input) == T_ARRAY) ? 1 : 0; -} - -%typemap(typecheck) const qpid::types::Variant const & { - $1 = (TYPE($input) == T_FLOAT || - TYPE($input) == T_STRING || - TYPE($input) == T_FIXNUM || - TYPE($input) == T_BIGNUM || - TYPE($input) == T_TRUE || - TYPE($input) == T_FALSE) ? 1 : 0; -} - -%typemap(typecheck) bool { - $1 = (TYPE($input) == T_TRUE || - TYPE($input) == T_FALSE) ? 1 : 0; -} - - - -%typemap (typecheck, precedence=SWIG_TYPECHECK_INTEGER) uint64_t { - $1 = FIXNUM_P($input); -} - |